cosmos-query-helper

An adapter & interface designed to bring the power & speed of precision-oriented Cosmos queries to JavaScript developers without requiring any knowledge of SQL or how Cosmos/DocumentDB works.

Usage no npm install needed!

<script type="module">
  import cosmosQueryHelper from 'https://cdn.skypack.dev/cosmos-query-helper';
</script>

README

cosmos-query-helper

cosmos-query-helper is an adapter & interface designed to easily bring the power & speed of precision-oriented Cosmos queries to JavaScript developers. You do not require any knowledge of SQL, T-SQL, the special JavaScript-like SQL of Cosmos/DocumentDB, or how Cosmos/DocumentDB works to use this package.

Features!

  • Perform simple SELECT and WHERE queries against Cosmos using a simple JavaScript interface.
  • Shunt the load of data filtering and processing into Cosmos/DocumentDB (where it belongs!) instead of getting a large set of data and then parsing through it in node (which is very slow). The only limit to how fast Cosmos processes your queries is how low you set its throughput in Azure Portal.
  • Connect to DocumentDB using the simple, built-in DocumentDBOptions and DocumentDBAdapter without having to go through the hassle of learning how to use the documentdb npm package.

Expected Future Updates

  • Write Unit Tests!
  • Query against Cosmos using familiar JavaScript-esque array operations.
  • Support for from and join.
  • Support for complex, nested operations.
  • More comprehensive set of supported options & features for DocumentDB.
  • Organize the documentation a little better.

Updates

  • 08/02/2018 - implemented Fluent design pattern, added basic support for .includes(), updated documentation with changes.
  • 08/02/2018 - removed necessity of escaped quotations for strings in .is() and .includes().
  • 08/03/2018 - updated errors in the documentation pertaining to the selects[] and wheres[], added the missing and() function (oops!); the default operator for a where() is AND.
  • 08/03/2018 - added basic support for .within(), updated documentation, minor bug-fixes.
  • 08/08/2018 - added support for arrayLength() with respect to a WHERE clause, basic support for the most commonly used conditionals: (>, <, >=, <=) as functions, updated documentation, and minor bug-fixes (specifically pertaining to or and and statements).
  • 08/20/2018 - added support for arrayLength() with respect to a SELECT clause, updated documentation
  • 08/20/2018 - updated DocumentDBAdapter.query() to receive a second, nullable parameter which determines whether Cosmos's extra properties should be deleted, updated documentation.
  • 09/06/2018 - added optional overwriteItem boolean parameter to DocumentDBAdapter.updateItem()

How To Use

Installation

cosmos-query-helper was developed using Node.js v8.9.4. If you use it with an earlier version of Node, I make no guarantees as to how well it will work, if it works at all.

Dependencies

  • documentdb
$ npm install documentdb
$ npm install cosmos-query-helper

Class Definition

Most npm packages don't tell you the list of available functions and their uses, but fortunately for you, this isn't most npm packages!

Classes

  • CosmosQuery
  • DocumentDBAdapter
  • DocumentDBOptions

Functions NOTE: All propertyNames and names must be of type string.

  • CosmosQuery

    • new CosmosQuery( databaseAdapter ) - creates a new CosmosQuery object which is linked to the database specified in the databaseAdapter parameter, which should be of type DocumentDBAdapter.
    • construct() - creates a query from the selects[] and wheres[] and returns it as a string.
    • hydrate( cosmosQuery ) - copies the databaseAdapter, selects[], and wheres[] from the specified cosmosQuery
    • run( retainCosmosProps = false ) - creates a query using construct() and submits it to the database specified in the databaseAdapter. Optional parameter retainCosmosParams determines whether or not the extra properties added by Cosmos will be deleted ( _rid, _self, _etag, _attachments, _ts ).
    • toString() - returns a JSON representation of this object.
    • valueOf() - returns a JSON representation of this object.

    Operations:

    • select( propertyName ) - creates a Select object and adds it to the CosmosQuery.selects[].
      • arrayLength() - returns the selected property's length; the selected property must be an array.
      • as( name ) - gives the selected property name as an alias when data for this query is returned from CosmosQuery.run().
    • where( propertyName ) - creates a Where object (the default operation is AND) and adds it to the CosmosQuery.wheres[].
      • Standard Operations:
        • is( value ) - takes any primitive data-type, and returns only the data in which the whereed property is equal to the specified value.
        • isGreaterThan( value ) - takes any primitive data-type, and returns only the data in which the whereed property is greater than the specified value.
        • isGreaterThanOrEqualTo( value ) - takes any primitive data-type, and returns only the data in which the whereed property is greater than or equal to the specified value.
        • isLessThan( value ) - takes any primitive data-type, and returns only the data in which the whereed property is less than the specified value.
        • isLessThanOrEqualTo( value ) - takes any primitive data-type, and returns only the data in which the whereed property is less than or equal to the specified value.
      • Array Operations
        • arrayLength() - gets the length of an array, if the whered property is an array.
        • includes( value ) - takes any primitive data-type, and returns only the data in which the whereed property includes the specified value. NOTE: Does not support nested, complex operations.
        • within( primitivesArray ) - takes an array of primitives, and returns only the data where the specified primitivesArray[] includes the whereed property. NOTE: Does not support nested, complex operations.
      • Conditional Operations
        • and( propertyName ) - creates an AND Where object and adds it to the CosmosQuery.wheres[]. NOTE: Does not support nested, complex operations.
        • or( propertyName ) - creates an OR Where object and adds it to the CosmosQuery.wheres[]. NOTE: Does not support nested, complex operations.
  • DocumentDBAdapter

    • new DocumentDbAdapter( databaseName, collectionName, options ) - takes in databaseName and collectionName as strings, and options as DocumentDBOptions in preparation for establishing a connection to DocumentDB (see connect())
    • async connect() - establishes a connection to the DocumentDB database and collection specified in the constructor.
    • async query( queryString ) - processes a CosmosDB query, if passed in as a string, and returns the results.
    • Basic CRUD operations:
      • async addItem( id, item )
      • async deleteItem( id )
      • async getItem( id )
      • async updateItem( id, item, overwriteItem = false )
  • DocumentDBOptions

    • new DocumentDBOptions( documentDBHostURL, authenticationKey )

Example(s)

let helper = require('cosmos-query-helper');

let test = async function()
{
    //First, set up your DocumentDBOptions
    let azureHostUrl = 'https://test-documentdb-database.documents.azure.com:443/';
    let azureAuthKey = 'base64stringSA9GJAS0D9GN0903909GAM09DG09J09M==';
    let options = new helper.DocumentDBOptions( azureHostUrl, azureAuthKey );

  //Then, set up your documentdb adapter.
    let database = 'MyDocumentDBDatabase';
    let collection = 'MyDocumentDBCollectionOfPeople';
    let peopleAdapter = new helper.DocumentDBAdapter( database, collection, options );
    await peopleAdapter.connect();

    //Create a query.
    let cq = new helper.CosmosQuery(peopleAdapter);
    cq.select("Name");
    cq.select("State");
    cq.select("EmailAddress").as("Email");
    cq.select("Eyes").as("EyeColor");
    console.log(cq.selects);
    
    console.log(`Query: ${cq.construct()}`);
    
    cq.where("ZipCode").is(62019);
    console.log(cq.wheres);
    
    console.log(`Query: ${cq.construct()}`);
    
    let people = await cq.run();
    console.log(people);
    
    //After you run a query, you can continue to alter it as much as you would like.
    let peopleWithShoeSizes = [];
    cq.select("ShoeSize").as("Shoe");
    cq.run().then( function( resolved )
    {
        peopleWithShoeSizes = resolved;
        console.log(peopleWithShoeSizes);
    }
    
    //You can create as many queries as you want from a single adapter. Here, I've reused the adapter from above.
    let emailQuery = new helper.CosmosQuery(peopleAdapter); 
    
    //You can use the Fluent pattern to string operations together ad infinitum.
    emailQuery
      .select('EmailAddress').as('Email')
      .select("House.Garage.Cars").arrayLength().as("Num_Cars")
      .select('Name')
      .where('Personality').is("friendly")
      .and("Dispositions").includes("warm")      //<== No need to escape quotes for strings
      .or('House.Garage.Cars').arrayLength().isGreaterThan(2);    
        
    let nicePeopleToEmail = await emailQuery.run();
};

test();