
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
Cassanova is an object modeler for Cassandra CQL.
First install node.js and cassandra. Then:
git clone https://github.com/incroud/cassanova.git
cd cassanova
npm install
var Cassanova = require('cassanova'),
table = Cassanova.Table("users", Cassanova.Schema({
id : Cassanova.SchemaType.UUID().PRIMARY_KEY(),
username : Cassanova.SchemaType.TEXT(),
})),
UserModel = Cassanova.Model("userModel", table),
myUserModel = new UserModel();
myUserModel.save({id:"80398220-e461-11e3-ac10-0800200c9a66", username:"jeboothjr"}, function(err, result){
});
Cassanova.createClient(options)
A client is created as follows. Internally, the driver manages connections to Cassandra. options.hosts, options.port and options.keyspace are required. For additional options, please refer to the driver documentation : nodejs-driver
var Cassanova = require('cassanova'),
options = {
hosts: ['localhost'], /* An array of hosts */
port:9042,
keyspace: "cassanova_ks", /* The keyspace to use. */
username: "", /* optional, the username for cassandra */
password: "", /* optional, the password for cassandra */
skipSchemaValidation: true /* optional, defaults to false. Bypasses schema validation */
};
Cassanova.createClient(options);
Cassanova.connect([options], callback)
Creating a connection is as follows. This is not necessary as the driver will automatically connect when a query is executed. If you do not create a client first, you can optional pass in the same options as you would when creating a client and one will be automatically created for you. If options are used, options.hosts, options.port and options.keyspace are required.
var Cassanova = require('cassanova');
Cassanova.connect({
hosts : ['localhost'],
port : 9042,
keyspace : 'cassanova_ks'
},function(error, success){
});
Cassanova.isConnected()
Returns a Boolean as to whether or not the client is connected.
Cassanova.disconnect([callback])
Disconnnects the client from the pool. The optional callback will be executed when the client is disconnected.
The events from the driver are bubbled up through to Cassanova. Following that pattern, the level being passed to the listener can be info or error.
Cassanova.on('log', function(level, message) {
console.log(level, message);
});
Cassanova.SchemaType.PRIMARY_KEY(keys)
Assigns primary keys for the Schema. keys can be either a String, Array or Multi-Dimensional Array containing matching column names.
When attached to another SchemaType as in Cassanova.SchemaType.UUID().PRIMARY_KEY(), no arguments are used. The schema types contain validation, although not all of the validation is complete or is simple as of right now.
Cassanova.SchemaType.ASCII()
Cassanova.SchemaType.BIGINT()
Cassanova.SchemaType.BLOB()
Cassanova.SchemaType.BOOLEAN()
Cassanova.SchemaType.COUNTER()
Cassanova.SchemaType.DECIMAL()
Cassanova.SchemaType.DOUBLE()
Cassanova.SchemaType.FLOAT()
Cassanova.SchemaType.INET()
Cassanova.SchemaType.INT()
Cassanova.SchemaType.LIST()
Cassanova.SchemaType.MAP()
Cassanova.SchemaType.SET()
Cassanova.SchemaType.TEXT()
Cassanova.SchemaType.TIMESTAMP()
Cassanova.SchemaType.UUID()
Cassanova.SchemaType.TIMEUUID()
Cassanova.SchemaType.VARCHAR()
Cassanova.SchemaType.VARINT()
new Cassanova.Schema(obj)
Creates a Cassanova Schema, where obj refers to an object that contains key/value pairs of the column names and data types.
var userTablechema = Cassanova.Schema({
id : Cassanova.SchemaType.UUID().PRIMARY_KEY(),
username : Cassanova.SchemaType.TEXT(),
});
new Cassanova.Table(name, schema)
Creates a Cassanova Table, where name refers to the actual table name in Cassandra and schema is a Cassanova.Schema.
A table defines the schema to be associated with the model. The table is validated to ensure that all of the type are set appropriately and that a PRIMARY KEY has been set correctly. Schema types are used to validate against the actual data in the model. Composite and partition keys are supported..
var Cassanova = require('cassanova'),
userTablechema = Cassanova.Schema({
id : Cassanova.SchemaType.UUID().PRIMARY_KEY(),
username : Cassanova.SchemaType.TEXT(),
}),
userTable = Cassanova.Table("users", userTablechema),
infoTableSchema = Cassanova,Schema({
id : Cassanova.SchemaType.UUID(),
email : Cassanova.SchemaType.TEXT(),
username : Cassanova.SchemaType.TEXT(),
PRIMARY_KEY: Schema.Type.PRIMARY_KEY([["id", "email"], "username"])
}),
infoTable = Cassanova.Table("info", infoTableSchema);
new Cassanova.Model(name, table)
Creates a Cassanova Model where name is a unique identifier to retreive the model from Cassanova and table is a Cassanova.Table.
A model requires a table to be associated with it when it is being defined. When creating the model, the first argument must be unique and refers to the name of the model which you can use to retrieve it.
var schema = Cassanova.Schema({
id : Cassanova.SchemaType.UUID(),
email : Cassanova.SchemaType.TEXT(),
username : Cassanova.SchemaType.TEXT(),
PRIMARY_KEY: Schema.Type.PRIMARY_KEY("id")
}),
table = Cassanova.Table("user", schema),
UserModel = Cassanova.model("userModel", table);
Once a model is created you can access via the same way, without requiring the table. An error will br thrown if you attempt to overwrite a model with a new table.
var myUserModel = new Cassanova.model("userModel")();
myUserModel.save({id:'71c20c30-e461-11e3-ac10-0800200c9a66', firstname:"James", lastname:"Booth"}, function(err, result){
});
By default, a model has the following methods: find, save, findAllBy, delete and CQL.
var myUserModel = new Cassanova.model("userModel")();
userModel.find({id,'71c20c30-e461-11e3-ac10-0800200c9a66'}, function(err, result){});
userModel.save({id:'71c20c30-e461-11e3-ac10-0800200c9a66', username:"jeboothjr"}, function(err, result){});
userModel.findAllBy('username','James', function(err, result){});
userModel.delete({id,'71c20c30-e461-11e3-ac10-0800200c9a66'}, function(err, result){});
userModel.CQL('SELECT * FROM users', function(err, result){});
You can create separate model files, if needed, and customise your queries.
infoModel.js
var Cassanova = require('cassanova'),
userInfoSchema = new Cassanova.Schema({
userid : Cassanova.SchemaType.TIMEUUID(),
info_date : Cassanova.SchemaType.TIMESTAMP(),
info : Cassanova.SchemaType.TEXT(),
PRIMARY_KEY : Cassanova.SchemaType.PRIMARY_KEY(["userid", "attempt_date"])
}),
userInfoTable = Cassanova.Table("user_by_info", userInfoSchema),
infoModel = Cassanova.Model("userAuthLogModel", userInfoTable);
infoModel.prototype.getRecentInfo = function(id, count, callback){
var query = this.Query();
query.SELECT("*").WHERE_EQUALS("userid", id).ORDER_BY("info_date", true).LIMIT(count);
query.execute(callback);
return query;
};
new Cassanova.Query(client, table, [query])
Creates a Cassanova Query where client is a Cassanova.client, table is a Cassanova.Table to which the queries will be made and 'query' is an optional raw CQL string. If the raw string is included, you have the ability to chain off of that raw CQL.
var query = new Query(Cassanova.Client, Cassanova.Table("users"), "SELECT * FROM users");
query.WHERE().EQUALS("location", "california").execute(function(err, result){ });
var query = new Query(Cassanova.Client, Cassanova.Table("users"), "SELECT * FROM users");
query.WHERE("firstname").IN(["john", "carl"]).execute(function(err, result){ });
There are a variety of ways that queries can be executed.
As seen in some of the earlier examples, the model contains a CQL method where you can execute a raw CQL statement.
userModel.CQL('SELECT * FROM users', function(err, result){});
The model also contains a query object by which raw or chained CQL can be executed.
infoModel.prototype.getRecentInfo = function(id, count, callback){
this.query.SELECT("*").WHERE_EQUALS("userid", id).ORDER_BY("info_date", true).LIMIT(count).execute(callback);
}
infoModel.Query().SELECT("*").WHERE_EQUALS("userid", "71c20c30-e461-11e3-ac10-0800200c9a66").ORDER_BY("info_date", true).LIMIT(count).execute(function(err, result){ });
Complex queries can be done against the model by chaining the cql methods together.
personModel.find({firstname:"John"}).AND().EQUALS("age", 37).execute(function(err, result){});
personModel.find({lastname:"Doe"}).ORDER_BY("join_date", true).LIMIT(10).execute(function(err, result){});
Below is a list of the supported CQL query clauses and predicates. Bold indicates the output when that method is called.
clone()
Takes the current value of the query and creates a new query using that as base.
clear()
Clears the query value.
execute([callback])
Executes the CQL statement.
CQL(cql_str)
Sets the base of the CQL statement to the value of cql_str.
Below are the supported chainable query methods, showing the resulting string from each.
//.SELECT(selector) - Chainable.
SELECT * FROM users
//.INSERT(obj) - Chainable.
INSERT INTO users (firstname, lastname) VALUES ('james', 'booth');
//.DELETE(selector) - Chainable.
DELETE firstname, lastname FROM users;
//.WHERE() - Chainable.
WHERE
//.WHERE(key) - Chainable
WHERE firstname
//.WHERE_EQUALS(key, value) - Chainable.
WHERE firstname = 'james';
//.EQUALS(key, value)` - Chainable.
firstname = 'james'
//.AND() - Chainable.
AND
//.AND(key) - Chainable.
AND firstname
//.GT(key, value) - Chainable.
age > 21
//.GTE(key, value) - Chainable.
age >= 21
//.LT(key, value) - Chainable.
age < 21
//.LTE(key, value) - Chainable.
age <= 21
//.IN(options) - Chainable. A single value or an Array of values.
IN (123, 456);
//.IN(key, options) - Chainable. Optional key parameter.
userid IN (123, 456)
//.LIMIT(value) - Chainable.
LIMIT 10
//.ALLOW_FILTERING() - Chainable.
ALLOW FILTERING
//.ORDER_BY(column, doDescend) - Chainable.
ORDER BY (ASC)
//.USING_TTL(duration) - Chainable.
USING_TTL 86400
//.USING_TIMESTAMP(timestamp) - Chainable.
USING TIMESTAMP 1405446044378
//.COUNT(value, [doChain]) - Optionally Chainable.
COUNT(*)
//.COLUMN_TOKEN(columnName, [doChain]) - Optionally Chainable.
TOKEN(username)
//.VALUE_TOKEN(value, [doChain]) - Optionally Chainable.
TOKEN(123)
//.AS(key, alias, [doChain]) - Optionally Chainable.
userid AS id
Addition information regarding the methods below can be found in the node-cassandra-cql driver documentation.
Cassanova.execute(query, [options], callback)
query is a Cassanova.Query object, options current supports consistency where the value is one of Cassanova.consistencies.
Cassanova.executeAsPrepared(query, [options], callback)
query is a Cassanova.Query object, options current supports consistency where the value is one of Cassanova.consistencies.
Cassanova.executeBatch(queries, [options], callback)
query is a Cassanova.Query object, options current supports consistency where the value is one of Cassanova.consistencies.
Cassanova.executeEachRow(query, [options], rowCallback, endCallback)
query is a Cassanova.Query object, options current supports consistency where the value is one of Cassanova.consistencies. rowCallback(n, row) is called for each row as soon as the first chunk of the last field is received, where n is the index of the row. endCallback(err, rowLength) is called when all rows have been received or there is an error retrieving the row.
Cassanova.executeStreamField(query, [options], rowCallback, [endCallback])
query is a Cassanova.Query object, options current supports consistency where the value is one of Cassanova.consistencies. rowCallback(n, row, streamField) is called for each row as soon as the first chunk of the last field is received, where n is the index of the row. endCallback(err, rowLength) is called when all rows have been received or there is an error retrieving the row.
Cassanova.executeStream(query, [options], [callback])
query is a Cassanova.Query object, options current supports consistency where the value is one of Cassanova.consistencies.
Cassanova.consistencies
The consistencies used for queries. Defaults to quorum.
any one two three quorum all localQuorum eachQuorum localOne
In the root of the repo is a file, CQL.js, which is a command-line utility to run scripts against the database. Instructions can be found by running the following :
node CQL --help
The validation on some of the data types is simplistic or non-existent (list, map, set). These need to be fleshed out.
The may be some functionality in the driver that was overlooked.
Not every CQL command has been implemented.
I was using this to debug and experiment around, so I left it in. Below is some simple usage. You can also start the repl in --debug or --debug-brk and step through any of the code.
Take a look at the test/EndToEndTest.js file. There are a lot of examples in there.
//Create the keyspace in Cassandra first:
//CREATE KEYSPACE cassanova WITH REPLICATION = { 'class' : 'SimpleStrategy', 'replication_factor' : 1 };
$ node repl
$ var opts = {
"hosts" : ["localhost"],
"port" : 9042
"keyspace" : "cassanova"
};
$ Cassanova.connect(opts, function(err, result){
console.log(err || "Connected");
});
$ var q = Cassanova.Query().CQL("SELECT * FROM system.local;");
q.execute(function(err, result){
console.log(result.length);
console.log(result[0]);
});
cassanova is distributed under the MIT license.
Feel free to join in and support the project!
Check the Issue tracker
FAQs
An object modeler for Cassandra CQL.
We found that cassanova demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.