Comparing version 0.0.0 to 0.1.3
{ | ||
"name": "meadow", | ||
"version": "0.0.0", | ||
"version": "0.1.3", | ||
"description": "A data access library.", | ||
@@ -27,2 +27,4 @@ "main": "source/Meadow.js", | ||
"chai": "2.0.0", | ||
"codeclimate-test-reporter": "0.0.4", | ||
"coveralls": "^2.11.2", | ||
"istanbul": "0.3.5", | ||
@@ -32,8 +34,9 @@ "mocha": "2.1.0" | ||
"dependencies": { | ||
"foxhound": "0.0.0", | ||
"biguint-format": "1.0.0", | ||
"bunyan": "1.3.3", | ||
"flake-idgen": "1.0.0", | ||
"async": "^0.9.0", | ||
"fable": "^0.1.6", | ||
"foxhound": "0.0.9", | ||
"is-my-json-valid": "^2.10.1", | ||
"mysql2": "0.15.2", | ||
"underscore": "1.7.0" | ||
} | ||
} |
@@ -1,5 +0,10 @@ | ||
# Meadow | ||
Meadow | ||
====== | ||
A Javascript Data Broker. | ||
_Do not use this yet._ You've been warned. | ||
[![Code Climate](https://codeclimate.com/github/stevenvelozo/meadow/badges/gpa.svg)](https://codeclimate.com/github/stevenvelozo/meadow) [![Coverage Status](https://coveralls.io/repos/stevenvelozo/meadow/badge.svg?branch=master)](https://coveralls.io/r/stevenvelozo/meadow?branch=master) [![Build Status](https://travis-ci.org/stevenvelozo/meadow.svg?branch=master)](https://travis-ci.org/stevenvelozo/meadow) [![Dependency Status](https://david-dm.org/stevenvelozo/meadow.svg)](https://david-dm.org/stevenvelozo/meadow) [![devDependency Status](https://david-dm.org/stevenvelozo/meadow/dev-status.svg)](https://david-dm.org/stevenvelozo/meadow#info=devDependencies) | ||
_Do not use this yet._ | ||
@@ -10,15 +10,2 @@ /** | ||
// We use Underscore.js for utility | ||
var libUnderscore = require('underscore'); | ||
// The logger uses Bunyan to write logs | ||
var libLog = require('./Logger.js'); | ||
// Each query object gets a UUID, using flake-idgen and biguint-format | ||
var libFlakeIDGen = require('flake-idgen'); | ||
var flakeIDGen = new libFlakeIDGen(); | ||
var libIntFormat = require('biguint-format') | ||
// TODO: Load parameters for FlakeID generation from a .json config if it exists | ||
// FoxHound is the default query generator | ||
var libFoxHound = require('foxhound'); | ||
/** | ||
@@ -30,25 +17,565 @@ * Meadow Data Broker Library | ||
*/ | ||
var libAsync = require('async'); | ||
var libUnderscore = require('underscore') | ||
// Multi server query generation | ||
var libFoxHound = require('foxhound'); | ||
var Meadow = function() | ||
{ | ||
function createNew(pScope, pSchema) | ||
function createNew(pFable, pScope, pJsonSchema, pSchema) | ||
{ | ||
// A universally unique identifier for this object | ||
var _UUID = libIntFormat(flakeIDGen.next(), 'hex', { prefix: '0x' }); | ||
// If a valid Fable object isn't passed in, return a constructor | ||
if ((typeof(pFable) !== 'object') || (!pFable.hasOwnProperty('fable'))) | ||
{ | ||
return {new: createNew}; | ||
} | ||
var _Fable = pFable; | ||
// Make sure there is a valid data broker set | ||
_Fable.settingsManager.fill({MeadowProvider:'None'}); | ||
// The scope for this broker. This is the only internal state for this object. | ||
var _Scope = 'Unknown'; | ||
var _IDUser = 0; | ||
// The scope of this broker. | ||
var _Scope = (typeof(pScope) === 'string') ? pScope : 'Unknown'; | ||
// The schema for this broker | ||
var _Schema = require('./Meadow-Schema.js').new(pJsonSchema, pSchema); | ||
// The query for this broker | ||
var _Query = libFoxHound.new(_Fable).setScope(_Scope); | ||
// The data provider | ||
var _Provider = false; | ||
var _ProviderName = false; | ||
// The default identifier for this broker. | ||
// This is what is used for the automated endpoint queries | ||
// For example the 198 in GET http://myapi.com/Widget/198 | ||
// | ||
// Our development model prefers IDWidget as the column name for the default identifier. | ||
var _DefaultIdentifier = 'ID'+_Scope; | ||
/** | ||
* Clone the current FoxHound Query into a new Query object, copying all | ||
* parameters as the new default. Clone also copies the log level. | ||
* Load the schema and metadata from a package file | ||
* | ||
* @method createQuery | ||
* @return {Object} Returns a Query object. This is chainable. | ||
* @method loadFromPackage | ||
* @return {Object} Returns a new Meadow, or false if it failed | ||
*/ | ||
var createQuery = function() | ||
var loadFromPackage = function(pPackage) | ||
{ | ||
return libFoxHound.clone().setScope(_Scope); | ||
// Use the package loader to grab the configuration objects and clone a new Meadow. | ||
var tmpPackage = false; | ||
try | ||
{ | ||
tmpPackage = require(pPackage); | ||
} | ||
catch(pError) | ||
{ | ||
_Fable.log.error('Error loading Fable package', {Package:pPackage}); | ||
return false; | ||
} | ||
// Spool up a new Meadow object | ||
var tmpNewMeadow = createNew(_Fable); | ||
// Safely set the parameters | ||
if (typeof(tmpPackage.Scope) === 'string') | ||
{ | ||
tmpNewMeadow.setScope(tmpPackage.Scope); | ||
} | ||
if (typeof(tmpPackage.DefaultIdentifier) === 'string') | ||
{ | ||
tmpNewMeadow.setDefaultIdentifier(tmpPackage.DefaultIdentifier); | ||
} | ||
if (Array.isArray(tmpPackage.Schema)) | ||
{ | ||
tmpNewMeadow.setSchema(tmpPackage.Schema); | ||
} | ||
if (typeof(tmpPackage.JsonSchema) === 'object') | ||
{ | ||
tmpNewMeadow.setJsonSchema(tmpPackage.JsonSchema); | ||
} | ||
if (typeof(tmpPackage.DefaultObject) === 'object') | ||
{ | ||
tmpNewMeadow.setDefault(tmpPackage.DefaultObject) | ||
} | ||
return tmpNewMeadow; | ||
} | ||
/** | ||
* Set the scope | ||
* | ||
* @method setScope | ||
* @return {Object} Returns the current Meadow for chaining. | ||
*/ | ||
var setScope = function(pScope) | ||
{ | ||
_Scope = pScope; | ||
_Query.setScope(pScope); | ||
return this; | ||
}; | ||
/** | ||
* Set the user ID for inserts and updates | ||
* | ||
* @method setIDUser | ||
* @return {Object} Returns the current Meadow for chaining. | ||
*/ | ||
var setIDUser = function(pIDUser) | ||
{ | ||
_IDUser = pIDUser; | ||
return this; | ||
}; | ||
/** | ||
* Set the Provider for Query execution. | ||
* | ||
* This function expects a string, case sensitive, which matches the | ||
* provider filename | ||
* | ||
* @method setProvider | ||
* @param {String} pProviderName The provider for query generation. | ||
* @return {Object} Returns the current Meadow for chaining. | ||
*/ | ||
var setProvider = function(pProviderName) | ||
{ | ||
if (typeof(pProviderName) !== 'string') | ||
{ | ||
return setProvider('None'); | ||
} | ||
var tmpProviderModuleFile = './providers/Meadow-Provider-'+pProviderName+'.js'; | ||
try | ||
{ | ||
var tmpProviderModule = require(tmpProviderModuleFile).new(_Fable); | ||
_ProviderName = pProviderName; | ||
_Provider = tmpProviderModule; | ||
} | ||
catch (pError) | ||
{ | ||
_Fable.log.error({ProviderModuleFile:tmpProviderModuleFile, InvalidProvider:pProviderName, error:pError}, 'Provider not set - require load problem'); | ||
//setProvider('None'); | ||
} | ||
return this; | ||
}; | ||
setProvider(_Fable.settings.MeadowProvider); | ||
/** | ||
* Set the schema to be something else | ||
* | ||
* @method setSchema | ||
* @return {Object} This is chainable. | ||
*/ | ||
var setSchema = function(pSchema) | ||
{ | ||
_Schema.setSchema(pSchema); | ||
return this; | ||
}; | ||
/** | ||
* Set the Jsonschema to be something else | ||
* | ||
* @method setJsonSchema | ||
* @return {Object} This is chainable. | ||
*/ | ||
var setJsonSchema = function(pJsonSchema) | ||
{ | ||
_Schema.setJsonSchema(pJsonSchema); | ||
return this; | ||
}; | ||
/** | ||
* Set the default object to be something else | ||
* | ||
* @method setDefault | ||
* @return {Object} This is chainable. | ||
*/ | ||
var setDefault = function(pDefault) | ||
{ | ||
_Schema.setDefault(pDefault); | ||
return this; | ||
}; | ||
/** | ||
* Set the default identifier | ||
* | ||
* @method setDefaultIdentifier | ||
* @return {Object} This is chainable. | ||
*/ | ||
var setDefaultIdentifier = function(pDefaultIdentifier) | ||
{ | ||
_DefaultIdentifier = pDefaultIdentifier; | ||
return this; | ||
} | ||
/** | ||
* Create a record asynchronously, calling fCallBack with the marshalled record(s) or error in them at end | ||
* | ||
* TODO: Add a second behavior that creates records without returning them and takes an array of records. | ||
*/ | ||
var doCreate = function(pQuery, fCallBack) | ||
{ | ||
libAsync.waterfall( | ||
[ | ||
// Step 1: Get the record from the data source | ||
function (fStageComplete) | ||
{ | ||
pQuery.query.IDUser = _IDUser; | ||
// Make sure the user submitted a record | ||
if (!pQuery.query.records) | ||
{ | ||
return fStageComplete('No record submitted', pQuery, false); | ||
} | ||
// Merge in the default record with the passed-in record for completeness | ||
pQuery.query.records[0] = libUnderscore.extend(_Schema.defaultObject, pQuery.query.records[0]); | ||
// This odd lambda is to use the async waterfall without spilling logic into the provider create code complexity | ||
_Provider.Create(pQuery, function(){ fStageComplete(pQuery.result.error, pQuery); }); | ||
}, | ||
// Step 2: Marshal the record into a POJO | ||
function (pQuery, fStageComplete) | ||
{ | ||
if ( | ||
// The query wasn't run yet | ||
(pQuery.parameters.result.executed == false) || | ||
// The value is not set (it should be set to the value for our DefaultIdentifier) | ||
(pQuery.parameters.result.value === false) | ||
) | ||
{ | ||
return fStageComplete('Creation failed', pQuery, false); | ||
} | ||
var tmpIDRecord = pQuery.result.value; | ||
fStageComplete(pQuery.result.error, pQuery, tmpIDRecord); | ||
}, | ||
// Step 3: Read the record | ||
function (pQuery, pIDRecord, fStageComplete) | ||
{ | ||
var tmpQueryRead = pQuery.clone().addFilter(_DefaultIdentifier, pIDRecord); | ||
// This odd lambda is to use the async waterfall without spilling logic into the provider read code complexity | ||
_Provider.Read(tmpQueryRead, function(){ fStageComplete(tmpQueryRead.result.error, pQuery, tmpQueryRead); }); | ||
}, | ||
// Step 4: Marshal the record into a POJO | ||
function (pQuery, pQueryRead, fStageComplete) | ||
{ | ||
if ( | ||
// The value is not an array | ||
(!Array.isArray(pQueryRead.parameters.result.value)) || | ||
// There is not at least one record returned | ||
(pQueryRead.parameters.result.value.length < 1) | ||
) | ||
{ | ||
return fStageComplete('No record found after create.', pQuery, pQueryRead, false); | ||
} | ||
var tmpRecord = marshalRecordFromSourceToObject(pQueryRead.result.value[0]); | ||
fStageComplete(pQuery.result.error, pQuery, pQueryRead, tmpRecord); | ||
} | ||
], | ||
function(pError, pQuery, pQueryRead, pRecord) | ||
{ | ||
if (pError) | ||
{ | ||
_Fable.log.warn('Error during the create waterfall', {Error:pError, Query: pQuery.query}); | ||
} | ||
// Call the callback passed in with the record as the first parameter, query second. | ||
fCallBack(pError, pQuery, pQueryRead, pRecord); | ||
} | ||
); | ||
return this; | ||
} | ||
/** | ||
* Read a record asynchronously, calling fCallBack with the marshalled record(s) or error in them at end | ||
*/ | ||
var doRead = function(pQuery, fCallBack) | ||
{ | ||
// Read the record from the source | ||
libAsync.waterfall( | ||
[ | ||
// Step 1: Get the record from the data source | ||
function (fStageComplete) | ||
{ | ||
// This odd lambda is to use the async waterfall without spilling logic into the provider read code complexity | ||
_Provider.Read(pQuery, function(){ fStageComplete(pQuery.result.error, pQuery); }); | ||
}, | ||
// Step 2: Marshal the record into a POJO | ||
function (pQuery, fStageComplete) | ||
{ | ||
if ( | ||
// The value is not an array | ||
(!Array.isArray(pQuery.parameters.result.value)) || | ||
// There is not at least one record returned | ||
(pQuery.parameters.result.value.length < 1) | ||
) | ||
{ | ||
return fStageComplete('Invalid query result in Read', pQuery, false); | ||
} | ||
var tmpRecord = marshalRecordFromSourceToObject(pQuery.result.value[0]); | ||
// TODO: Add error handling for marshaling | ||
fStageComplete(pQuery.result.error, pQuery, tmpRecord); | ||
} | ||
], | ||
function(pError, pQuery, pRecord) | ||
{ | ||
if (pError) | ||
{ | ||
_Fable.log.warn('Error during the read waterfall', {Error:pError, Query: pQuery.query}); | ||
} | ||
// Call the callback passed in with the record as the first parameter, query second. | ||
fCallBack(pError, pQuery, pRecord); | ||
} | ||
); | ||
return this; | ||
} | ||
/** | ||
* Read many records asynchronously, calling fCallBack with the marshalled record(s) or error in them at end | ||
*/ | ||
var doReads = function(pQuery, fCallBack) | ||
{ | ||
// Read the record(s) from the source | ||
libAsync.waterfall( | ||
[ | ||
// Step 1: Get a record from the data source | ||
function (fStageComplete) | ||
{ | ||
// This odd lambda is to use the async waterfall without spilling logic into the provider read code complexity | ||
_Provider.Read(pQuery, function(){ fStageComplete(pQuery.result.error, pQuery); }); | ||
}, | ||
// Step 2: Marshal all the records into a POJO asynchronously | ||
function (pQuery, fStageComplete) | ||
{ | ||
if ( | ||
// The value is not an array | ||
(!Array.isArray(pQuery.parameters.result.value)) || | ||
// There is not at least one record returned | ||
(pQuery.parameters.result.value.length < 1) | ||
) | ||
{ | ||
return fStageComplete('No records read.', pQuery, false); | ||
} | ||
var tmpRecords = []; | ||
libAsync.each | ||
( | ||
pQuery.parameters.result.value, | ||
function(pRow, pQueueCallback) | ||
{ | ||
tmpRecords.push(marshalRecordFromSourceToObject(pRow)); | ||
pQueueCallback(); | ||
}, | ||
function() | ||
{ | ||
// Now complete the waterfall | ||
fStageComplete(pQuery.result.error, pQuery, tmpRecords); | ||
} | ||
); | ||
} | ||
], | ||
function(pError, pQuery, pRecord) | ||
{ | ||
if (pError) | ||
{ | ||
_Fable.log.warn('Error during the read multiple waterfall', {Error:pError, Query: pQuery.query}); | ||
} | ||
fCallBack(pError, pQuery, pRecord); | ||
} | ||
); | ||
return this; | ||
} | ||
/** | ||
* Update a record asynchronously, calling fCallBack with the marshalled record(s) or error in them at end | ||
*/ | ||
var doUpdate = function(pQuery, fCallBack) | ||
{ | ||
// Update the record(s) from the source | ||
libAsync.waterfall( | ||
[ | ||
// Step 1: Update the record | ||
function (fStageComplete) | ||
{ | ||
pQuery.query.IDUser = _IDUser; | ||
// Make sure the user submitted a record | ||
if (!pQuery.query.records) | ||
{ | ||
return fStageComplete('No record submitted', pQuery, false); | ||
} | ||
// Make sure there is a default identifier | ||
if (!pQuery.query.records[0].hasOwnProperty(_DefaultIdentifier)) | ||
{ | ||
return fStageComplete('Automated update missing default identifier', pQuery, false); | ||
} | ||
// Now see if there is anything in the schema that is an Update action that isn't in this query | ||
for (var i = 0; i < _Schema.schema.length; i++) | ||
{ | ||
switch (_Schema.schema[i].Type) | ||
{ | ||
case 'UpdateIDUser': | ||
case 'UpdateDate': | ||
pQuery.query.records[0][_Schema.schema[i].Column] = false; | ||
break; | ||
} | ||
} | ||
// Set the update filter | ||
pQuery.addFilter(_DefaultIdentifier, pQuery.query.records[0][_DefaultIdentifier]); | ||
// This odd lambda is to use the async waterfall without spilling logic into the provider read code complexity | ||
_Provider.Update(pQuery, function(){ fStageComplete(pQuery.result.error, pQuery); }); | ||
}, | ||
// Step 2: Check that the record was updated | ||
function (pQuery, fStageComplete) | ||
{ | ||
if ( | ||
// The query wasn't run yet | ||
(pQuery.parameters.result.executed == false) || | ||
// The value is not an object | ||
(typeof(pQuery.parameters.result.value) !== 'object') | ||
) | ||
{ | ||
return fStageComplete('No record created.', pQuery, false); | ||
} | ||
fStageComplete(pQuery.result.error, pQuery); | ||
}, | ||
// Step 3: Read the record | ||
function (pQuery, fStageComplete) | ||
{ | ||
// We can clone the query, since it has the criteria for the update in it already (filters survive a clone) | ||
var tmpQueryRead = pQuery.clone(); | ||
// This odd lambda is to use the async waterfall without spilling logic into the provider read code complexity | ||
_Provider.Read(tmpQueryRead, function(){ fStageComplete(tmpQueryRead.result.error, pQuery, tmpQueryRead); }); | ||
}, | ||
// Step 4: Marshal the record into a POJO | ||
function (pQuery, pQueryRead, fStageComplete) | ||
{ | ||
// This is a theoretical error ... it is pretty much impossible to simulate because | ||
// the waterfall error handling in step 3 catches problems in the underlying update. | ||
// Therefore we'll leave the guard commented out for now. But here for moral support. | ||
/* | ||
if ( | ||
// The value is not an array | ||
(!Array.isArray(pQueryRead.parameters.result.value)) || | ||
// There is not at least one record returned | ||
(pQueryRead.parameters.result.value.length < 1) | ||
) | ||
{ | ||
return fStageComplete('There was an issue loading a record after save.', pQuery, pQueryRead, false); | ||
} | ||
*/ | ||
var tmpRecord = marshalRecordFromSourceToObject(pQueryRead.result.value[0]); | ||
// TODO: Add error handling for marshaling | ||
fStageComplete(pQuery.result.error, pQuery, pQueryRead, tmpRecord); | ||
} | ||
], | ||
function(pError, pQuery, pQueryRead, pRecord) | ||
{ | ||
if (pError) | ||
{ | ||
_Fable.log.warn('Error during Update waterfall', {Error:pError, Query: pQuery.query}); | ||
} | ||
fCallBack(pError, pQuery, pQueryRead, pRecord); | ||
} | ||
); | ||
return this; | ||
} | ||
/** | ||
* Delete a record asynchronously, calling fCallBack with the marshalled record(s) or error in them at end | ||
*/ | ||
var doDelete = function(pQuery, fCallBack) | ||
{ | ||
// TODO: Check if this recordset has implicit delete tracking | ||
// Delete the record(s) from the source | ||
libAsync.waterfall( | ||
[ | ||
// Step 1: Delete the record | ||
function (fStageComplete) | ||
{ | ||
// This odd lambda is to use the async waterfall without spilling logic into the provider read code complexity | ||
_Provider.Delete(pQuery, function(){ fStageComplete(pQuery.result.error, pQuery, pQuery.result.value); }); | ||
} | ||
], | ||
function(pError, pQuery, pRecord) | ||
{ | ||
if (pError) | ||
{ | ||
_Fable.log.warn('Error during Count waterfall', {Error:pError, Query: pQuery.query}); | ||
} | ||
fCallBack(pError, pQuery, pRecord); | ||
} | ||
); | ||
return this; | ||
} | ||
/** | ||
* Count a record asynchronously, calling fCallBack with the marshalled record(s) or error in them at end | ||
*/ | ||
var doCount = function(pQuery, fCallBack) | ||
{ | ||
// Count the record(s) from the source | ||
libAsync.waterfall( | ||
[ | ||
// Step 1: Get the record from the data source | ||
function (fStageComplete) | ||
{ | ||
// This odd lambda is to use the async waterfall without spilling logic into the provider read code complexity | ||
_Provider.Count(pQuery, function(){ fStageComplete(pQuery.result.error, pQuery); }); | ||
}, | ||
// Step 2: Marshal the record into a POJO | ||
function (pQuery, fStageComplete) | ||
{ | ||
if ( | ||
// The value is not a number | ||
(typeof(pQuery.parameters.result.value) !== 'number') | ||
) | ||
{ | ||
return fStageComplete('Count did not return valid results.', pQuery, false); | ||
} | ||
fStageComplete(pQuery.result.error, pQuery, pQuery.result.value); | ||
} | ||
], | ||
function(pError, pQuery, pCount) | ||
{ | ||
fCallBack(pError, pQuery, pCount); | ||
} | ||
); | ||
return this; | ||
} | ||
/** | ||
* Take the stored representation of our object and stuff the proper values | ||
* into our record, translating where necessary. | ||
*/ | ||
var marshalRecordFromSourceToObject = function(pRecord) | ||
{ | ||
// Create an object from the default schema object | ||
var tmpNewObject = libUnderscore.extend({}, _Schema.defaultObject); | ||
// Now marshal the values from pRecord into tmpNewObject, based on schema | ||
_Provider.marshalRecordFromSourceToObject(tmpNewObject, pRecord, _Schema.schema); | ||
//_Fable.log.trace('Validation', {Value:tmpNewObject, Validation:_Schema.validateObject(tmpNewObject)}) | ||
// Now return the new object | ||
return tmpNewObject; | ||
} | ||
/** | ||
* Container Object for our Factory Pattern | ||
@@ -58,14 +585,32 @@ */ | ||
{ | ||
createQuery: createQuery, | ||
doCreate: doCreate, | ||
doRead: doRead, | ||
doReads: doReads, | ||
doUpdate: doUpdate, | ||
doDelete: doDelete, | ||
doCount: doCount, | ||
validateObject: _Schema.validateObject, | ||
setProvider: setProvider, | ||
setIDUser: setIDUser, | ||
// Schema management | ||
loadFromPackage: loadFromPackage, | ||
// | ||
setScope: setScope, | ||
setSchema: setSchema, | ||
setJsonSchema: setJsonSchema, | ||
setDefault: setDefault, | ||
setDefaultIdentifier: setDefaultIdentifier, | ||
// Factory | ||
new: createNew | ||
}); | ||
/** | ||
* Scope | ||
* Entity Scope -- usually the name of the entity it represents | ||
* | ||
* @property scope | ||
* @type String | ||
* @type string | ||
*/ | ||
@@ -75,28 +620,66 @@ Object.defineProperty(tmpNewMeadowObject, 'scope', | ||
get: function() { return _Scope; }, | ||
set: function(pScope) { _Scope = pScope; }, | ||
enumerable: true | ||
}); | ||
/** | ||
* Entity Schema | ||
* | ||
* @property schema | ||
* @type object | ||
*/ | ||
Object.defineProperty(tmpNewMeadowObject, 'schema', | ||
{ | ||
get: function() { return _Schema.schema; }, | ||
enumerable: true | ||
}); | ||
/** | ||
* Json Schema | ||
* | ||
* @property schema | ||
* @type object | ||
*/ | ||
Object.defineProperty(tmpNewMeadowObject, 'jsonSchema', | ||
{ | ||
get: function() { return _Schema.jsonSchema; }, | ||
enumerable: true | ||
}); | ||
/** | ||
* Universally Unique Identifier | ||
* Query (FoxHound) object | ||
* | ||
* @property uuid | ||
* @type string | ||
* This always returns a cloned query, so it's safe to get queries with a simple: | ||
* var tmpQuery = libSomeFableObject.query; | ||
* | ||
* and not expect leakage of basic (cap, begin, filter, dataelements) cloned values. | ||
* | ||
* @property query | ||
* @type object | ||
*/ | ||
Object.defineProperty(tmpNewMeadowObject, 'uuid', | ||
Object.defineProperty(tmpNewMeadowObject, 'query', | ||
{ | ||
get: function() { return _UUID; }, | ||
get: function() | ||
{ | ||
var tmpQuery = _Query.clone(); | ||
// Set the default schema | ||
tmpQuery.query.schema = _Schema.schema; | ||
return tmpQuery; | ||
}, | ||
enumerable: true | ||
}); | ||
/** | ||
* Provider Name | ||
* | ||
* @property providerName | ||
* @type object | ||
*/ | ||
Object.defineProperty(tmpNewMeadowObject, 'providerName', | ||
{ | ||
get: function() { return _ProviderName; }, | ||
enumerable: true | ||
}); | ||
_Fable.addServices(tmpNewMeadowObject); | ||
var __initialize = function () | ||
{ | ||
// TODO: Load a json file with any necessary config settings. | ||
}; | ||
__initialize(); | ||
return tmpNewMeadowObject; | ||
@@ -108,2 +691,2 @@ } | ||
module.exports = Meadow(); | ||
module.exports = new Meadow(); |
@@ -13,2 +13,40 @@ /** | ||
var libFable = require('fable'); | ||
var _TestAnimalJsonSchema = ( | ||
{ | ||
"title": "Animal", | ||
"description": "A creature that lives in a meadow.", | ||
"type": "object", | ||
"properties": { | ||
"id": { | ||
"description": "The unique identifier for an animal", | ||
"type": "integer" | ||
}, | ||
"type": { | ||
"description": "The type of the animal", | ||
"type": "string" | ||
}, | ||
"name": { | ||
"description": "The animal's name", | ||
"type": "string" | ||
}, | ||
"age": { | ||
"description": "How old the animal is in days", | ||
"type": "number", | ||
"minimum": 0, | ||
"exclusiveMinimum": true | ||
}, | ||
"tags": { | ||
"type": "array", | ||
"items": { | ||
"type": "string" | ||
}, | ||
"minItems": 0, | ||
"uniqueItems": true | ||
} | ||
}, | ||
"required": ["id", "name", "age"] | ||
}); | ||
suite | ||
@@ -19,4 +57,2 @@ ( | ||
{ | ||
var testMeadow = false; | ||
setup | ||
@@ -26,3 +62,2 @@ ( | ||
{ | ||
testMeadow = require('../source/Meadow.js'); | ||
} | ||
@@ -41,2 +76,3 @@ ); | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(); | ||
Expect(testMeadow).to.be.an('object', 'Meadow should initialize as an object directly from the require statement.'); | ||
@@ -47,13 +83,119 @@ } | ||
( | ||
'There should be some basic metadata on the class parameters', | ||
'There should be some basic metadata on the class properties', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable); | ||
Expect(testMeadow).to.have.a.property('scope') | ||
.that.is.a('string'); // Scope is always a string | ||
Expect(testMeadow).to.have.a.property('uuid') | ||
.that.is.a('string') | ||
.that.is.not.empty; | ||
Expect(testMeadow).to.have.a.property('schema') | ||
.that.is.a('object'); | ||
} | ||
); | ||
test | ||
( | ||
'Initialize with values', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable, 'Animal', _TestAnimalJsonSchema); | ||
Expect(testMeadow.scope) | ||
.to.equal('Animal'); | ||
Expect(testMeadow.jsonSchema.title) | ||
.to.equal('Animal'); | ||
} | ||
); | ||
test | ||
( | ||
'Alternative initialization', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable) | ||
.setScope('Animal') | ||
.setSchema(_TestAnimalJsonSchema); | ||
Expect(testMeadow.scope) | ||
.to.equal('Animal'); | ||
var tmpValidationResults = testMeadow.validateObject({id:10, type:'bunny', name:'foofoo', age:3}); | ||
Expect(tmpValidationResults.Valid) | ||
.to.equal(true); | ||
} | ||
); | ||
test | ||
( | ||
'Validate a proper animal', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable, 'Animal', _TestAnimalJsonSchema); | ||
var tmpValidationResults = testMeadow.validateObject({id:10, type:'bunny', name:'foofoo', age:3}); | ||
Expect(tmpValidationResults.Valid) | ||
.to.equal(true); | ||
} | ||
); | ||
test | ||
( | ||
'Validate a messed up animal', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable, 'Animal', _TestAnimalJsonSchema); | ||
// Our zombie needs a name! | ||
var tmpValidationResults = testMeadow.validateObject({id:9, type:'zombie', age:3}); | ||
libFable.log.info('Bad Unnamed Zombie Validation Results', tmpValidationResults); | ||
Expect(tmpValidationResults.Valid) | ||
.to.equal(false); | ||
} | ||
); | ||
test | ||
( | ||
'Change provider', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable, 'Animal', _TestAnimalJsonSchema); | ||
Expect(testMeadow.providerName) | ||
.to.equal('None'); | ||
} | ||
); | ||
test | ||
( | ||
'Try to change to a bad provider', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable, 'Animal', _TestAnimalJsonSchema); | ||
Expect(testMeadow.providerName) | ||
.to.equal('None'); | ||
testMeadow.setProvider(); | ||
Expect(testMeadow.providerName) | ||
.to.equal('None'); | ||
testMeadow.setProvider('BADPROVIDERNAME'); | ||
Expect(testMeadow.providerName) | ||
.to.equal('None'); | ||
} | ||
); | ||
test | ||
( | ||
'Try to load from a json package', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable).loadFromPackage(__dirname+'/Animal.json'); | ||
Expect(testMeadow.scope) | ||
.to.equal('FableTest'); | ||
} | ||
); | ||
test | ||
( | ||
'Try to load from an empty json package', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable).loadFromPackage(__dirname+'/EmptyPackage.json'); | ||
Expect(testMeadow.scope) | ||
.to.equal('Unknown'); | ||
} | ||
); | ||
test | ||
( | ||
'Try to load from a bad json package', | ||
function() | ||
{ | ||
var testMeadow = require('../source/Meadow.js').new(libFable).loadFromPackage(__dirname+'/BadAnimal.json'); | ||
Expect(testMeadow) | ||
.to.equal(false); | ||
} | ||
); | ||
} | ||
@@ -60,0 +202,0 @@ ); |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
61423
16
2158
11
6
5
2
1
+ Addedasync@^0.9.0
+ Addedfable@^0.1.6
+ Addedis-my-json-valid@^2.10.1
+ Addedmysql2@0.15.2
+ Addedabort-controller@3.0.0(transitive)
+ Addedansicolors@0.2.1(transitive)
+ Addedasync@0.9.2(transitive)
+ Addedbase64-js@1.5.1(transitive)
+ Addedbn.js@2.0.0(transitive)
+ Addedbson@0.2.22(transitive)
+ Addedbuffer@6.0.3(transitive)
+ Addedbunyan-mongo@0.1.0(transitive)
+ Addedcardinal@0.4.4(transitive)
+ Addedcoffee-script@1.12.7(transitive)
+ Addeddouble-ended-queue@2.0.0-0(transitive)
+ Addedesprima@1.0.4(transitive)
+ Addedevent-target-shim@5.0.1(transitive)
+ Addedevents@3.3.0(transitive)
+ Addedfable@0.1.11(transitive)
+ Addedfable-log@0.1.3(transitive)
+ Addedfable-settings@0.0.3(transitive)
+ Addedfable-uuid@0.1.3(transitive)
+ Addedfoxhound@0.0.130.0.9(transitive)
+ Addedgenerate-function@2.3.1(transitive)
+ Addedgenerate-object-property@1.2.0(transitive)
+ Addedieee754@1.2.1(transitive)
+ Addedis-my-ip-valid@1.0.1(transitive)
+ Addedis-my-json-valid@2.20.6(transitive)
+ Addedis-property@1.0.2(transitive)
+ Addedjsonpointer@5.0.1(transitive)
+ Addedkerberos@0.0.9(transitive)
+ Addedlru-cache@2.5.0(transitive)
+ Addedmongodb@1.4.32(transitive)
+ Addedmysql2@0.15.2(transitive)
+ Addednamed-placeholders@0.1.3(transitive)
+ Addednan@1.6.21.8.4(transitive)
+ Addedprocess@0.11.10(transitive)
+ Addedreadable-stream@4.6.0(transitive)
+ Addedredeyed@0.4.4(transitive)
+ Addedsafe-buffer@5.2.1(transitive)
+ Addedstring_decoder@1.3.0(transitive)
+ Addedunderscore@1.13.7(transitive)
+ Addedxtend@4.0.2(transitive)
- Removedbiguint-format@1.0.0
- Removedbunyan@1.3.3
- Removedflake-idgen@1.0.0
- Removedfoxhound@0.0.0(transitive)
Updatedfoxhound@0.0.9