Skip to content

robpolak/cqlify

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

68 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CQLify

A ORM (Object-relational mapping) libraby for Cassandra ontop of the data-stax cassandra driver. This library will abstract the need to write raw insert/update/select statements.

Status : PRE-ALPHA

(use at your own risk!, higly unstable)

Current Version : 0.0.15

Installation

$ npm install cqlify

Creating a Connection

Uses all of the same connection options as the data-stax cassandra driver. Here is an exmple of a basic C*(Cassandra) database with basic authentication:

var cassandra = require('cassandra-driver');
var connectionOptions = {
    contactPoints: ["2.2.2.2","3.3.3.3"],
    keyspace: "keyspace",
    policies: {},
    authProvider: new cassandra.auth.PlainTextAuthProvider("user", "password")
};
var cqlify = require('./cqlify');
cqlify.createConnection(connectionOptions);

Creating a model

Now that you have a connection you can create a model. In your model you will specify the schema, which describes the format of your object. Let's take an example table:

Column Type
id timeuuid
first_name text
address text

user_model.js

var userModel = function(cqlify) {
    var schema = {
      id: {
        type: cqlify.types.TIMEUUID,
        key_type: cqlify.types.PRIMARY_KEY,
        key_order: 1
      },
      first_name: {
        type: cqlify.types.TEXT,
      },
      address: {
        type: cqlify.types.TEXT
      }
    };

    var model = cqlify.model(schema, {
      tableName: 'user'
    });

    model._pre(function(obj) {
      if(obj.isNew) {
        obj.id = cqlify.types.getTimeUuid().now();
      }
    });

    return model;
  };
  module.exports = userModel;
Supported Types
  1. TimeUUID - C* type
  2. TimeStamp - C* type
  3. Int - C* type
  4. BigInt - C* type
  5. Boolean - C* type
  6. UUID - C* type
  7. JSONTOTEXT - Propietry type which will allow you to specify your field as a JSON object. Cqlify will convert that object to JSON and store it as text in the DB.
  8. ENUMTOTEXT - Like JSON to text you can specify a Javascript enum value, and in turn cqlify will handle the conversions to text and back.
Mixed Support
  1. Map : Supported on Insert and Get.. will eventually support update with a future enhancement
  2. List : Supported on Insert and Get.. will eventually support update with a future enhancement
  3. Counter : No support.. to come.. you could an Int for now, however, need to build in logic for incremental updates.. i.e. "counter + 1"

Select

In this section we will cover how to select data using cqlify. It is a very easy process to select out data

Lookup with one field

    var user = new userModel(cqlify);  //create your model
    
    user.find([{
      name:'id', value: user.id, comparer: cqlify.comparer.EQUALS  //specify the query type and field name
    }], function(err, data) {
      if(err){
        //handle errors here
      }
      console.log(data[0].toObject()) //log the first object
    });

Lookup with multi-field, c always treats this as an AND*

    var user = new userModel(cqlify);  //create your model
		var query = {
			params: [
				{name:'id', value: 'idvalue', comparer: cqlify.comparer.EQUALS},
				{name:'first_name', value: 'first_name', comparer: cqlify.comparer.EQUALS},
			]
		};
    user.find(query, function(err, data) {
      if(err){
        //handle errors here
      }
      console.log(data[0].toObject()) //log the first object
    });
Comparer Types
  1. EQUALS : cqlify.types.EQUALS : Standard equals operator .. i.e. field="value"
  2. GREATER_THAN :cqlify.types.GREATER_THAN : count > 10
  3. LESS_THAN :cqlify.types.LESS_THAN : count < 10
  4. IN : cqlify.types.IN : value in ("value1","value2","value3)

Insert

  var user = new userModel(cqlify);
  user.id = cqlify.types.getTimeUuid().now();
  user.first_name = "Robert";
  user.address = "some address";
  var query = {};
  user.insert(query, function(err, data) {
      if(err){
        //handle errors here
      }
      console.log(data[0].toObject()) //log the first object
  });

Update

Here is an example of pulling a record from the database and then updating one field (address in this case).

    var user = new userModel(cqlify);
		var query = {
			params: [{
				name:'id', value: user.id, comparer: cqlify.comparer.EQUALS
			}]
		};
    user.find(query, function(err, data) {
      if (err) throw err;
      var user_from_db = data[0];
      user_from_db.address = "new address";
      user_from_db.update(
        [{name: 'id', value: user.id, comparer: cqlify.comparer.EQUALS}]  //specify the update criteria.. we could automate this in the future..
        , function (err, data) {
          if (err) throw err;
          console.log('saved user');
        });
    });

Using Counters

Counters are kind of a special animal when it comes to CQL.. To insert a Counter you actually have to do an Update.. even if it is new.. odd I know.. Counters must always be incremented or decremented, thus CQLify enforces a format like '+0' '+1' '-5' etc.. Thus, here is how you would create a new counter..

Model

  var pageCountModel = function() {
    var schema = {
      counter_value: {
        type: cqlify.types.COUNTER
      },
      url_name: {
        type: cqlify.types.TEXT
      },
      page_name: {
        type: cqlify.types.TEXT
      }
    };
    var opts = {
      tableName: 'counts'
    };
    var model = cqlify.model(schema, opts);
    return model;
  }();

Code

  var page = new pageCountModel();
  page.page_name = 'cnn';
  page.url_name =  'www.cnn.com';
  page._markClean();  //this is kind of a hack for now.. basically you never want the primary keys being marked as dirty, which then puts it on the update set.
  page.counter_value = "+0";  //must always increment or decrement .. cannot set a value

	var query = {
		params: [
			{name: "page_name", value: page.page_name, comparer: cqlify.comparer.EQUALS},
			{name: "url_name", value: page.url_name, comparer: cqlify.comparer.EQUALS},
		]
	};
  page.update(query, function(err, data) {
    if(err) {
      console.log('ERROR:' + err);
    }
  });

Validation

Out of the box we validate certain fields to ensure they meet the specification to insert into the database. The fields we do contstraint validation on :

  1. TimeUuid
  2. Text
  3. Int(Int32)
  4. bigint(Int64)
  5. Date
  6. Boolean
Custom Vaidation

All schema types allow for custom validation, all you need to do is add a "validators" array to a schema element.

Validate first name must be atleast 5 characters

  var userModel = function () {
    var schema = {
      id: {
        type: cqlify.types.TIMEUUID,
        key_type: cqlify.types.PRIMARY_KEY,
        key_order: 1
      },
      first_name: {
        type: cqlify.types.TEXT,
        validators: [
          function (obj) {
            if (obj && obj.length < 5){
              return cqlify.util.constructValidationMessage(false, "First name must be atleast 5 characters"); //construct the error message.
            }
            return true; //return back the object is valid
              
          }
        ]
      }
    }
  });
Ad-hoc validation

You can always validate manually by invoking the _validate method

var isValid = user._validate();

Author : Robert Polak

Bugs

See https://github.com/robpolak/cqlify/issues.

License

The MIT License (MIT)

Contributing - Totally welcome, just shoot me a message.