Skip to content

Commit

Permalink
feat: Added generators for feathers-objection & feathers-cassandra (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dekelev authored and daffl committed Sep 24, 2018
1 parent 74b31df commit c8b27d0
Show file tree
Hide file tree
Showing 14 changed files with 9,062 additions and 174 deletions.
6 changes: 4 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
sudo: false
sudo: required
language: node_js
install: npm install
script:
- npm test
- npm run test:generators
- if [ ! -z "$SAUCE_ACCESS_KEY" ]; then npm run test:client; fi
services: mongodb
services:
- mongodb
- cassandra
node_js:
- node
- '6'
Expand Down
52 changes: 48 additions & 4 deletions packages/generator-feathers/generators/connection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ module.exports = class ConnectionGenerator extends Generator {
const { connectionString, database, adapter } = this.props;
let parsed = {};

if (adapter === 'objection') {
this.dependencies.push('knex');
} else if (adapter === 'cassandra') {
this.dependencies.push('express-cassandra');
this.dependencies.push('cassanknex');
}

switch (database) {
case 'nedb':
this.dependencies.push('nedb');
Expand All @@ -52,7 +59,7 @@ module.exports = class ConnectionGenerator extends Generator {
case 'rethinkdb':
parsed = url.parse(connectionString);
this.dependencies.push('rethinkdbdash');

return {
db: parsed.path.substring(1, parsed.path.length),
servers: [
Expand Down Expand Up @@ -93,6 +100,30 @@ module.exports = class ConnectionGenerator extends Generator {
} : connectionString
};

case 'cassandra':
if (typeof connectionString !== 'string') {
return connectionString;
}

parsed = url.parse(connectionString);

return {
clientOptions: {
contactPoints: [parsed.hostname],
protocolOptions: { port: Number(parsed.port) || 9042 },
keyspace: parsed.path.substring(1, parsed.path.length),
queryOptions: { consistency: 1 }
},
ormOptions: {
defaultReplicationStrategy: {
class: 'SimpleStrategy',
replication_factor: 1
},
migration: 'alter',
createKeyspace: true
}
};

default:
throw new Error(`Invalid database '${database}'. Cannot assemble configuration.`);
}
Expand Down Expand Up @@ -138,7 +169,8 @@ module.exports = class ConnectionGenerator extends Generator {
{ name: 'PostgreSQL', value: 'postgres' },
{ name: 'RethinkDB', value: 'rethinkdb' },
{ name: 'SQLite', value: 'sqlite' },
{ name: 'SQL Server', value: 'mssql' }
{ name: 'SQL Server', value: 'mssql' },
{ name: 'Cassandra', value: 'cassandra' }
],
when (current) {
const answers = getProps(current);
Expand All @@ -153,6 +185,7 @@ module.exports = class ConnectionGenerator extends Generator {
case 'rethinkdb':
case 'memory':
case 'mongodb':
case 'cassandra':
setProps({ database: adapter });
return false;
case 'mongoose':
Expand Down Expand Up @@ -186,13 +219,21 @@ module.exports = class ConnectionGenerator extends Generator {
];
const sqlOptions = [
{ name: 'Sequelize', value: 'sequelize' },
{ name: 'KnexJS', value: 'knex' }
{ name: 'KnexJS', value: 'knex' },
{ name: 'Objection', value: 'objection' }
];
const cassandraOptions = [
{ name: 'Cassandra', value: 'cassandra' }
];

if (database === 'mongodb') {
return mongoOptions;
}

if (database === 'cassandra') {
return cassandraOptions;
}

// It's an SQL DB
return sqlOptions;
},
Expand All @@ -208,6 +249,7 @@ module.exports = class ConnectionGenerator extends Generator {
case 'nedb':
case 'rethinkdb':
case 'memory':
case 'cassandra':
return false;
}

Expand All @@ -228,7 +270,8 @@ module.exports = class ConnectionGenerator extends Generator {
postgres: `postgres://postgres:@localhost:5432/${databaseName}`,
rethinkdb: `rethinkdb://localhost:28015/${databaseName}`,
sqlite: `sqlite://${databaseName}.sqlite`,
mssql: `mssql://root:password@localhost:1433/${databaseName}`
mssql: `mssql://root:password@localhost:1433/${databaseName}`,
cassandra: `cassandra://localhost:9042/${databaseName}`
};

return defaultConnectionStrings[database];
Expand Down Expand Up @@ -320,6 +363,7 @@ module.exports = class ConnectionGenerator extends Generator {
// case 'oracle':
case 'postgres': // eslint-disable-line no-fallthrough
case 'rethinkdb':
case 'cassandra':
this.log(`Make sure that your ${database} database is running, the username/role is correct, and "${connectionString}" is reachable and the database has been created.`);
this.log('Your configuration can be found in the projects config/ folder.');
break;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const ExpressCassandra = require('express-cassandra');
const FeathersCassandra = require('feathers-cassandra');

module.exports = function (app) {
const connectionInfo = app.get('<%= database %>');
const models = ExpressCassandra.createClient(connectionInfo);
const cassandraClient = models.orm.get_system_client();

app.set('models', models);

cassandraClient.connect(err => {
if (err) throw err;

const cassanknex = require('cassanknex')({ connection: cassandraClient });

FeathersCassandra.cassanknex(cassanknex);

cassanknex.on('ready', err => {
if (err) throw err;
});

app.set('cassanknex', cassanknex);
});
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const { Model } = require('objection');

module.exports = function (app) {
const { client, connection } = app.get('<%= database %>');
const knex = require('knex')({ client, connection, useNullAsDefault: false });

Model.knex(knex);

app.set('knex', knex);
};
14 changes: 11 additions & 3 deletions packages/generator-feathers/generators/service/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ module.exports = class ServiceGenerator extends Generator {
}, {
name: 'RethinkDB',
value: 'rethinkdb'
}, {
name: 'Objection',
value: 'objection'
}, {
name: 'Cassandra',
value: 'cassandra'
}
]
}, {
Expand Down Expand Up @@ -90,7 +96,7 @@ module.exports = class ServiceGenerator extends Generator {
return this.prompt(prompts).then(answers => {
const parts = (answers.name || props.name)
.split('/')
// exclude route parameters from folder hierarchy i.e. /users/:id/roles
// exclude route parameters from folder hierarchy i.e. /users/:id/roles
.filter(part => !part.startsWith(':'));
const name = parts.pop();

Expand All @@ -113,7 +119,7 @@ module.exports = class ServiceGenerator extends Generator {
const camelName = _.camelCase(folder);
const serviceRequire = `const ${camelName} = require('./${folder}/${kebabName}.service.js');`;
const serviceCode = `app.configure(${camelName});`;

if(mainExpression.length !== 1) {
this.log
.writeln()
Expand Down Expand Up @@ -142,7 +148,9 @@ module.exports = class ServiceGenerator extends Generator {
mongoose: 'feathers-mongoose',
sequelize: 'feathers-sequelize',
knex: 'feathers-knex',
rethinkdb: 'feathers-rethinkdb'
rethinkdb: 'feathers-rethinkdb',
objection: 'feathers-objection',
cassandra: 'feathers-cassandra'
};
const serviceModule = moduleMappings[adapter];
const serviceFolder = [ this.libDirectory, 'services', ...subfolder, kebabName ];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// See https://express-cassandra.readthedocs.io/en/latest/schema/
// for more of what you can do here.
module.exports = function (app) {
const models = app.get('models');
const <%= camelName %> = models.loadSchema('<%= camelName %>', {
table_name: '<%= snakeName %>',
fields: {
id: 'int',
<% if(authentication.strategies.indexOf('local') !== -1) { %>
email: 'text',
password: {
type: 'text',
rule: {
required: true
}
},
<% } %><% authentication.oauthProviders.forEach(provider => { %>
<%= provider.name %>Id: 'text',
<% }); %>
},
key: ['id'],
custom_indexes: [
{
on: 'email',
using: 'org.apache.cassandra.index.sasi.SASIIndex',
options: {}
},
{
on: 'password',
using: 'org.apache.cassandra.index.sasi.SASIIndex',
options: {}
}
],
options: {
timestamps: true
}
}, function (err) {
if (err) throw err;
});

<%= camelName %>.syncDB(function (err) {
if (err) throw err;
});

return <%= camelName %>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// See https://express-cassandra.readthedocs.io/en/latest/schema/
// for more of what you can do here.
module.exports = function (app) {
const models = app.get('models');
const <%= camelName %> = models.loadSchema('<%= camelName %>', {
table_name: '<%= snakeName %>',
fields: {
id: 'int',
text: {
type: 'text',
rule: {
required: true
}
}
},
key: ['id'],
custom_indexes: [
{
on: 'text',
using: 'org.apache.cassandra.index.sasi.SASIIndex',
options: {}
}
],
options: {
timestamps: true
}
}, function (err) {
if (err) throw err;
});

<%= camelName %>.syncDB(function (err) {
if (err) throw err;
});

return <%= camelName %>;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// See https://vincit.github.io/objection.js/#models
// for more of what you can do here.
const { Model } = require('objection');

class <%= camelName %> extends Model {

static get tableName() {
return '<%= snakeName %>';
}

static get jsonSchema() {
return {
type: 'object',
required: ['password'],

properties: {
<% if(authentication.strategies.indexOf('local') !== -1) { %>
email: { type: ['string', 'null'] },
password: 'string',
<% } %><% authentication.oauthProviders.forEach(provider => { %>
<%= provider.name %>Id: { type: 'string' },
<% }); %>
}
};
}

$beforeInsert() {
this.createdAt = this.updatedAt = new Date().toISOString();
}

$beforeUpdate() {
this.updatedAt = new Date().toISOString();
}
}

module.exports = function (app) {
const db = app.get('knex');

db.schema.hasTable('<%= snakeName %>').then(exists => {
if (!exists) {
db.schema.createTable('<%= snakeName %>', table => {
table.increments('id');
<% if(authentication.strategies.indexOf('local') !== -1) { %>
table.string('email').unique();
table.string('password');
<% } %>
<% authentication.oauthProviders.forEach(provider => { %>
table.string('<%= provider.name %>Id');
<% }); %>
table.timestamp('createdAt');
table.timestamp('updatedAt');
})
.then(() => console.log('Created <%= snakeName %> table')) // eslint-disable-line no-console
.catch(e => console.error('Error creating <%= snakeName %> table', e)); // eslint-disable-line no-console
}
})
.catch(e => console.error('Error creating <%= snakeName %> table', e)); // eslint-disable-line no-console

return <%= camelName %>;
};
Loading

0 comments on commit c8b27d0

Please sign in to comment.