From 184c1902239ab14d84ca7be8451ead5b5ac5419d Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Mon, 20 May 2013 16:05:59 -0700 Subject: [PATCH] Bring up the schema loading from json docs --- examples/jdb-schemas.json | 15 +++++ examples/load-schemas.js | 19 ++++++ examples/schemas.json | 83 +++++++++++++++++++++++++ lib/adl-loader.js | 125 ++++++++++++++++++++++++++++++++++++++ lib/adl.js | 14 ++++- lib/hooks.js | 2 +- lib/model.js | 2 +- 7 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 examples/jdb-schemas.json create mode 100644 examples/load-schemas.js create mode 100644 examples/schemas.json create mode 100644 lib/adl-loader.js diff --git a/examples/jdb-schemas.json b/examples/jdb-schemas.json new file mode 100644 index 00000000..05dd5079 --- /dev/null +++ b/examples/jdb-schemas.json @@ -0,0 +1,15 @@ +{ + "title": { + "type": "String" + }, + "author": { + "type": "String", + "default": "Raymond" + }, + "body": "String", + "date": { + "type": "Date" + }, + "hidden": "Boolean", + "comments": ["String"] +} \ No newline at end of file diff --git a/examples/load-schemas.js b/examples/load-schemas.js new file mode 100644 index 00000000..09313246 --- /dev/null +++ b/examples/load-schemas.js @@ -0,0 +1,19 @@ +var path = require('path'); + +var loadSchemasSync = require('../lib/adl-loader').loadSchemasSync; + + +var models = loadSchemasSync(path.join(__dirname, 'jdb-schemas.json')); + +for (var s in models) { + var m = models[s]; + // console.dir(m); + console.log(new m()); +} + +models = loadSchemasSync(path.join(__dirname, 'schemas.json')); +for (var s in models) { + var m = models[s]; + // console.dir(m); + console.log(new m()); +} diff --git a/examples/schemas.json b/examples/schemas.json new file mode 100644 index 00000000..447726b4 --- /dev/null +++ b/examples/schemas.json @@ -0,0 +1,83 @@ +[ + { + "name": "Address", + "properties": { + "label": "string", + "street": "string", + "city": "string", + "zipCode": "string" + } + }, + + { + "name": "Account", + "properties": { + "id": "string", + "customer": { + "type": "Customer", + "association": { + "type": "belongsTo", + "inverse": "account" + } + }, + "balance": "number" + } + }, + + { + "name": "Customer", + "options": { + "oracle": { + "owner": "STRONGLOOP", + "table": "CUSTOMER" + } + }, + "properties": { + "id": { + "type": "number", + "id": true, + "doc": "Customer ID" + }, + "firstName": { + "type": "string", + "trim": true, + "required": true, + "oracle": { + "column": "FNAME", + "type": "VARCHAR", + "length": 32 + } + }, + "lastName": { + "type": "string", + "trim": true, + "required": true, + "oracle": { + "column": "LNAME", + "type": "VARCHAR", + "length": 32 + } + }, + "vip": { + "type": "boolean", + "doc": "indicate if the customer is a VIP", + "oracle": { + "column": "VIP", + "type": "CHAR", + "length": 1 + } + }, + "emails": [ + { + "type": "string", + "trim": true + } + ], + "address": { + "type": "Address" + }, + "account": "Account" + } + } + +] \ No newline at end of file diff --git a/lib/adl-loader.js b/lib/adl-loader.js new file mode 100644 index 00000000..1b0d77ea --- /dev/null +++ b/lib/adl-loader.js @@ -0,0 +1,125 @@ +var fs = require('fs') + , DataSource = require('./datasource').DataSource; + +// Built-in data types +var builtinTypes = { + 'string': String, + 'number': Number, + 'date': Date, + 'buffer': Buffer, + 'binary': Buffer, + 'boolean': Boolean, + 'any': DataSource.Any, + 'array': Array +} + +/** + * Resolve the type to be a function + * @param type + * @returns {*} + */ +function getSchemaType(type) { + if (!type) { + return type; + } + if (Array.isArray(type) && type.length > 0) { + var itemType = getSchemaType(type[0]); + if (typeof itemType === 'function') { + return [itemType]; + } + else return itemType; + } + if (typeof type === 'string') { + var schemaType = builtinTypes[type.toLowerCase()]; + if (schemaType) { + return schemaType; + } else { + return type; + } + } else if (type.constructor.name == 'Object') { + if (type.type) { + return getSchemaType(type.type); + } else { + throw new Error('Missing type property'); + } + } +} + +/** + * + * @param name + * @param properties + * @param associations + * @returns {*} + */ +function buildSchema(name, properties, associations) { + for (var p in properties) { + console.log(name + "." + p + ": " + properties[p]); + var type = getSchemaType(properties[p]); + if (typeof type === 'string') { + console.log('Association: ' + type); + associations.push({ + source: name, + target: type, + relation: Array.isArray(properties[p]) ? 'hasMany' : 'belongsTo', + as: p + }); + delete properties[p]; + } else { + properties[p] = type; + } + } + return properties; +} + + +/** + * Load ADL schemas from a json doc + * @param schemaFile The schema json file + * @returns A map of schemas keyed by name + */ +function loadSchemasSync(schemaFile, dataSource) { + + if(!dataSource) { + dataSource = new DataSource('memory'); + } + + var models = {}; + + var schemas = JSON.parse(fs.readFileSync(schemaFile)); + if (Array.isArray(schemas)) { + // An array already + } else if (schemas.properties && schemas.name) { + schemas = [schemas]; + } else { + schemas = [ + { + name: 'Anonymous', + properties: schemas + } + ]; + } + + var associations = []; + for (var s in schemas) { + var name = schemas[s].name; + console.log('Loading ' + name); + var jdbSchema = buildSchema(name, schemas[s].properties, associations); + console.dir(jdbSchema); + var model = dataSource.define(name, jdbSchema); + console.dir(model); + models[name.toLowerCase()] = model; + } + + for (var i = 0; i < associations.length; i++) { + var association = associations[i]; + var sourceModel = models[association.source.toLowerCase()]; + var targetModel = models[association.target.toLowerCase()]; + if (sourceModel && targetModel) { + sourceModel[association.relation](targetModel, {as: association.as}); + } + } + return models; +} + +exports.loadSchemasSync = loadSchemasSync; diff --git a/lib/adl.js b/lib/adl.js index 1fcb4d8b..88a68168 100644 --- a/lib/adl.js +++ b/lib/adl.js @@ -2,7 +2,7 @@ * Module dependencies */ var ModelBaseClass = require('./model.js'); -var DataAccessObject = require('./dao.js'); +// var DataAccessObject = require('./dao.js'); var List = require('./list.js'); var EventEmitter = require('events').EventEmitter; var util = require('util'); @@ -15,7 +15,7 @@ var existsSync = fs.existsSync || path.existsSync; * Export public API */ exports.Schema = Schema; -exports.ADL= new Schema(); + // exports.ModelBaseClass = ModelBaseClass; /** @@ -25,6 +25,7 @@ var slice = Array.prototype.slice; Schema.Text = function Text() {}; Schema.JSON = function JSON() {}; +Schema.Any = function Any() {}; Schema.types = {}; Schema.registerType = function (type) { @@ -33,6 +34,14 @@ Schema.registerType = function (type) { Schema.registerType(Schema.Text); Schema.registerType(Schema.JSON); +Schema.registerType(Schema.Any); + +Schema.registerType(String); +Schema.registerType(Number); +Schema.registerType(Boolean); +Schema.registerType(Date); +Schema.registerType(Buffer); +Schema.registerType(Array); /** @@ -321,3 +330,4 @@ function defineReadonlyProp(obj, key, value) { }); } +exports.ADL = new Schema(); \ No newline at end of file diff --git a/lib/hooks.js b/lib/hooks.js index 1f7de668..03b30972 100644 --- a/lib/hooks.js +++ b/lib/hooks.js @@ -6,7 +6,7 @@ exports.Hookable = Hookable; /** * Hooks mixins for ./model.js */ -var Hookable = require('./dao.js'); +var Hookable = require('./model.js'); /** * List of hooks available diff --git a/lib/model.js b/lib/model.js index fe0b8628..99dd5a6f 100644 --- a/lib/model.js +++ b/lib/model.js @@ -8,7 +8,7 @@ module.exports = ModelBaseClass; */ var util = require('util'); var List = require('./list.js'); - +require('./hooks.js'); var BASE_TYPES = ['String', 'Boolean', 'Number', 'Date', 'Text'];