question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Object model surface area and nomenclature changes (v2)

See original GitHub issue

Goals

For each of the objects we operate on (database, collection, document, etc.), we want to move their operations off of DocumentClient and onto objects which represent those operations. We also want to rename those objects to better capture their functionality in today’s Cosmos terms (as opposed to legacy Document DB terms). We want the SDK to be easy to use & grok (understand).

Nomenclature updates

Current New Notes
DocumentDB Cosmos
DocumentClient CosmosClient
DatabaseAccount DatabaseAccount No Change
Database Database No Change
User ? Still in discussion
User.* ? Still in discussion
Collection Container
Document Item
Attachment Attachment No Change
Conflict ?
Feed ?
Offers ?
PartitionKeyRanges ?
Stored Procedures ?
Triggers ?
User Defined Functions ?

Surface Area updates

A few notable changes:

  • We’ll be moving the operations for a given object to the parent of that object. (aka container will have operations for readItem on it).
  • We’ll have a “fluent” style API which will replace the current URI based model of referencing objects. (aka await client.getDatabase("foo").getContainer("bar").readItem("baz"))
  • “builder” operations (basically get operations) will be sync and not talk to server
  • QCRRUD operations will be async (and will talk to the server)

We take some inspiration from REST models, but have a goal of being easy to understand/code versus being technically pure.

Examples

Query Items

const {result: items} = await client
    .getDatabase(databaseName)
    .getContainer(containerName)
    .queryItems("select * from C")
    .toArray();

Note: Might want to support queryItems<T> (for interfaces) to allow users to get help on the interface of items.

Pass a container object around

Register collection with DI framework

ioc.register("todoCollection", client.getDatabase(databaseName).getContainer(containerName));

Consume container in route logic

public async getTodos(@Injectable("todoContainer") Container todoContainer) {
    const {result: todos} = await todoContainer.readItems();
    return todos;
}

Objects

Heirarchy

  • A given object can have many children

    • “A database has collections” (1:N)
  • A given object only has 1 parent

    • “A collection has a database” (1:1)
  • client

    • database account
    • offer
    • databases
      • database
      • users
        • user
          • permissions
            • permission
      • containers -container - items - item - attachments - attachment - triggers - trigger - user defined functions - user defined function - stored procedures - stored procedure

Overall pattern will be:

const parent // any given parent object
parent.children.query // query many
parent.children.read //read many
parent.child("foo").read //read one
parent.child("foo").replace // replace one
parent.child.parent

CosmosClient

  • #.getDatabaseAccount(options?: RequestOptions) => Promise<DatabaseAccount>
  • #.databases: Databases
  • #.offers: Offers

DatabaseAccount

???

Databases

  • #.getDatabase(id: string) => Database
  • #.query(query: string | SqlQuerySpec, options?: FeedOptions) => QueryIterator<DatabaseDefinition>
  • #.create(body: object, options?: RequestOptions) => Promise<Response<DatabaseDefinition>>
  • #.read(options?: FeedOptions) => QueryIteratory<DatabaseDefinition>
    • TBD: Worried about confusion with getDatabase

Database

  • #.id
  • #.containers: Containers
  • #.read(options?: RequestOptions) => Promise<Response<DatabaseDefinition>>
  • #.replace(options?: RequestOptions) => Promise<Response<DatabaseDefinition>>
  • #.delete(options?: RequestOptions) => Promise<Response<DatabaseDefinition>>

Containers

  • #.getContainer(id: string) => Container
  • #.query(query: string | SqlQuerySpec, options?: FeedOptions) => QueryIterator<ContainerDefinition>
  • #.create(body: object, options?: RequestOptions) => Promise<Response<ContainerDefinition>>
  • #.read(options?: FeedOptions) => QueryIterator<ContainerDefinition>

Container

  • #.id
  • #.database: Database
  • #.items: Items
  • #.read(name: string, options?: RequestOptions) => Promise<Response<ContainerDefinition>>
  • #.replace(name: string, body: ContainerDefinition, options?: RequestOptions) => Promise<Response<ContainerDefinition>>
  • #.delete(name: string, options?: RequestOptions) => Promise<Response<ContainerDefinition>>

Items

  • #.getItem(id: string, pk?: string) => Item
  • #.query(query: string | SqlQuerySpec, options?: FeedOptions) => QueryIterator<?>
  • #.read(options?: FeedOptions) => QueryIterator<?>
  • #.create<T>(body: T, options?: RequestOptions) => Promise<Response<T>>
  • #.upsert<T>(body: T, options?: RequestOptions) => Promise<Response<T>>

Item

  • #.id
  • #.primaryKey
  • #.container: Container
  • #.readItem<T>(id: string, options?: RequestOptions) => Promise<Response<T>>
  • #.replaceItem<T>(id: string, body: T, options?: RequestOptions) => Promise<Response<T>> - Do we need this id? How do we sniff out if we’re using a partition resolver?
  • #.deleteItem<T>(id: string, options?: ResquestOptions) => Promise<Response<T>>

StoredProcedures

  • #.getStoredProcedure(id: string) => StoredProcedure
  • #.query(query: string | SqlQuerySpec, options?: FeedOptions) => QueryIterator<StoredProcedureDefinition>
  • #.read(options?: FeedOptions) => QueryIterator<StoredProcedureDefinition>
  • #.create(body: StoredProcedureDefinition, options?: RequestOptions) => Promise<Response<StoredProcedureDefinition>>
  • #.upsert(body: StoredProcedureDefinition, options?: RequestOptions) => Promise<Response<StoredProcedureDefinition>>

StoredProcedure

  • #.id
  • #.container: Container
  • #.read(options?: RequestOptions) => Promise<Response<StoredProcedureDefinition>>
  • #.replace(body: StoredProcedureDefinition, options?: RequestOptions) => Promise<Response<StoredProcedureDefinition>>
  • #.delete(options?: RequestOptions) => Promise<Response<StoredProcedureDefinition>>
  • #.execute<T>(params?: any[], options?: RequestOptions) => Promise<Response<T>>

Triggers

  • #.getTrigger(id: string) => Trigger
  • #.query(query: string | SqlQuerySpec, options?: FeedOptions) => QueryIterator<TriggerDefinition>
  • #.read(options?: FeedOptions) => QueryIterator<TriggerDefinition>
  • #.create(body: TriggerDefinition, options?: RequestOptions) => Promise<Response<TriggerDefinition>>
  • #.upsert(body: TriggerDefinition, options?: RequestOptions) => Promise<Response<TriggerDefinition>>

Trigger

  • #.id
  • #.container: Container
  • #.read(options?: RequestOptions) => Promise<Response<TriggerDefinition>>
  • #.replace(body: TriggerDefinition, options?: RequestOptions) => Promise<Response<TriggerDefinition>>
  • #.delete(options?: RequestOptions) => Promise<Response<TriggerDefinition>>

UserDefinedFunctions

  • #.getUserDefinedFunction(id: string) => UserDefinedFunction
  • #.query(query: string | SqlQuerySpec, options?: FeedOptions) => QueryIterator<UserDefinedFunctionDefinition>
  • #.read(options?: FeedOptions) => QueryIterator<UserDefinedFunctionDefinition>
  • #.create(body: UserDefinedFunctionDefinition, options?: RequestOptions) => Promise<Response<UserDefinedFunctionDefinition>>
  • #.upsert(body: UserDefinedFunctionDefinition, options?: RequestOptions) => Promise<Response<UserDefinedFunctionDefinition>>

UserDefinedFunction

  • #.id
  • #.container: Container
  • #.read(id: string, options?: RequestOptions) => Promise<Response<UserDefinedFunctionDefinition>>
  • #.replace(id: string, body: UserDefinedFunctionDefinition, options?: RequestOptions) => Promise<Response<UserDefinedFunctionDefinition>>
  • #.delete(id: string, options?: RequestOptions) => Promise<Response<UserDefinedFunctionDefinition>>

Offers

  • #.getOffer(id: string) => Offer
  • #.queryOffers(query: string | SqlQuerySpec, options?: FeedOptions) => QueryIterator<OfferDefinition>
  • #.readOffers(options?: FeedOptions) => QueryIterator<OfferDefinition>

Offer

  • #.id
  • #.readOffer(id: string, options?: RequestOptions) => Promise<Response<OfferDefinition>>
  • #.replaceOffer(body: OfferDefinition, options?: RequestOptions) => Promise<Response<OfferDefinition>>

User

  • #.id
  • ???

Open Questions

  • Most of the API is top down, but can we put bottom up calls where it makes sense?

    For instance, client.readDatabase("foo") instead being client.database("foo").read()

  • What are we doing with Users?

  • Are we going to continue to support partition resolver?

Change Log

  • 2018-06-13: Modified the API structure to isolate operations to their representative objects

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Comments:16 (15 by maintainers)

github_iconTop GitHub Comments

1reaction
ausfeldtcommented, Jun 6, 2018

Assuming that there is not another contending name, I prefer “collection” over “container”. Container I have mostly seen in a GUI context. It does feel awkward.

0reactions
christopherandersoncommented, Jul 20, 2018

This feedback has been addressed or moved to independent issues, so I’m closing.

Read more comments on GitHub >

github_iconTop Results From Across the Web

KB5004442—Manage changes for Windows DCOM Server ...
The Distributed Component Object Model (DCOM) Remote Protocol is a protocol for exposing application objects using remote procedure calls (RPCs).
Read more >
SURFACE
SURFACE. This keyword data block is used to define the amount and composition of each surface in a surface assemblage. The composition of...
Read more >
Get area - PyMOLWiki
get_area calculates the surface area in square Angstroms of the selection given. Note that the accessibility is assessed in the context of ...
Read more >
Surface-area-to-volume ratio - Wikipedia
The surface-area-to-volume ratio, also called the surface-to-volume ratio and variously denoted sa/vol or SA:V, is the amount of surface area per unit ...
Read more >
Surface Area Formulas For Different Geometrical ... - Byju's
Surface area formulas in geometry refer to the lateral surface and total surface areas of different geometrical objects. To recall, the surface area...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found