Skip to content

Commit

Permalink
stricter type check logic added to fixtures
Browse files Browse the repository at this point in the history
  • Loading branch information
izelnakri committed Oct 23, 2017
1 parent d7a9081 commit 685fc7d
Show file tree
Hide file tree
Showing 6 changed files with 412 additions and 117 deletions.
4 changes: 2 additions & 2 deletions examples/photo-album/memserver/models/photo.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Model from '../../../../lib/mem-server/model';

export default Object.assign(Model, {

export default Model({
});
62 changes: 56 additions & 6 deletions lib/mem-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@ if (!fs.existsSync('memserver')) {
throw new Error(chalk.red('/memserver/server.js doesn\'t exist for this directory!'));
}

console.log(process.cwd());
const Server = require(`${process.cwd()}/memserver/server`).default; // NOTE: make this ES6 import
const modelFileNames = fs.readdirSync('memserver/models');
const modelFileNames = fs.readdirSync(`${process.cwd()}/memserver/models`);
const targetNamespace = ENVIRONMENT_IS_NODE ? global : window;

targetNamespace.MemServer = {
Expand Down Expand Up @@ -67,6 +66,7 @@ function colorStatusCode(statusCode) {
function registerModels(modelFileNames) {
return modelFileNames.reduce((result, modelFileName) => {
const ModelName = stringUtils.classify(modelFileName.slice(0, -3));

result[ModelName] = require(`${process.cwd()}/memserver/models/${modelFileName}`).default; // NOTE: make this ES6 import
result[ModelName].modelName = ModelName;

Expand All @@ -79,15 +79,65 @@ function resetDatabase(models) {
const fileName = stringUtils.dasherize(inflect.pluralize(modelName));
const path = `${process.cwd()}/memserver/fixtures/${fileName}.js`;

if (fs.existsSync(path)) {
result[modelName] = require(path).default; // NOTE: make this ES6 import
// TODO: maybe check ids must exist and all of them are integers
} else {
if (!fs.existsSync(path)) {
result[modelName] = []

return result;
}

const fixtureModels = require(path).default; // NOTE: make this ES6 import

if (fixtureModels.length === 0) {
result[modelName] = []

return result;
}

const modelPrimaryKey = fixtureModels.reduce((existingPrimaryKey, model) => {
const primaryKey = getModelPrimaryKey(model, existingPrimaryKey, modelName);

if (!primaryKey) {
throw new Error(chalk.red(`MemServer DATABASE ERROR: At least one of your ${modelName} fixtures missing a primary key. Please make sure all your ${modelName} fixtures have either id or uuid primaryKey`));
}

return primaryKey;
}, null);

targetNamespace.MemServer.Models[modelName].primaryKey = modelPrimaryKey;
result[modelName] = fixtureModels;

return result;
}, {});
}


function getModelPrimaryKey(model, existingPrimaryKeyType, modelName) {
if (!existingPrimaryKeyType) {
const primaryKey = model.id || model.uuid;

if (!primaryKey) {
return;
}

existingPrimaryKeyType = model.id ? 'id' : 'uuid';

return primaryKeyTypeCheck(existingPrimaryKeyType, primaryKey, modelName);
}

return primaryKeyTypeCheck(existingPrimaryKeyType, model[existingPrimaryKeyType], modelName);
}

// NOTE: move this to utils
function primaryKeyTypeCheck(targetPrimaryKeyType, primaryKey, modelName) {
const primaryKeyType = typeof primaryKey;

if (targetPrimaryKeyType === 'id' && (primaryKeyType !== 'number')) {
throw new Error(chalk.red(`MemServer ${modelName} model primaryKeyType is 'id'. Instead you've tried to enter ${primaryKey} with ${primaryKeyType}`));
} else if (targetPrimaryKeyType === 'uuid' && (primaryKeyType !== 'string')) {
throw new Error(chalk.red(`MemServer ${modelName} model primaryKeyType is 'uuid'. Instead you've tried to enter ${primaryKey} with ${primaryKeyType}`));
}

return targetPrimaryKeyType;
}

// TODO: BUILD A CLI
159 changes: 81 additions & 78 deletions lib/mem-server/model.js
Original file line number Diff line number Diff line change
@@ -1,86 +1,89 @@
const ENVIRONMENT_IS_NODE = typeof global === 'object';
const targetNamespace = ENVIRONMENT_IS_NODE ? global : window;

export default {
modelName: '',
attributes: [],
find(id) {
const models = targetNamespace.MemServer.DB[this.modelName] || [];

return models.find((model) => model.id === id);
},
findAll(options={}) {
const keys = Object.keys(options);
const models = targetNamespace.MemServer.DB[this.modelName] || [];

if (keys.length === 0) {
return models;
}

return models.filter((model) => comparison(model, options, keys, 0));
},
findBy(options) {
const keys = Object.keys(options);
const models = targetNamespace.MemServer.DB[this.modelName] || [];
console.log('models are:', models);

return models.find((model) => comparison(model, options, keys, 0));
},
insert(options) { // NOTE: what if there is same id?
const models = targetNamespace.MemServer.DB[this.modelName] || [];

// TODO: auto-increment ids
const defaultAttributes = this.attributes.reduce((result, attribute) => {
// TODO: enable functions
result[attribute] = this[attribute];
}, {});

const targetAttributes = Object.assign(defaultAttributes, options);

models.push(targetAttributes);
},
bulkInsert(count, options) {
return Array.from({ length: count }).map(() => this.insert(options));
},
update(record) {
const targetRecord = record.id ? this.find(record.id) : this.findBy({ uuid: record.uuid });

if (!targetRecord) {
throw new Error('[MemServer] $Model.update(record) requires id or uuid primary key to update a record');
}

const targetIndex = models.indexOf(targetRecord);
export default function(options) {
return Object.assign({}, {
modelName: '',
primaryKey: '',
attributes: [],
find(id) {
const models = targetNamespace.MemServer.DB[this.modelName] || [];

return models.find((model) => model.id === id);
},
findAll(options={}) {
const keys = Object.keys(options);
const models = targetNamespace.MemServer.DB[this.modelName] || [];

if (keys.length === 0) {
return models;
}

return models.filter((model) => comparison(model, options, keys, 0));
},
findBy(options) {
const keys = Object.keys(options);
const models = targetNamespace.MemServer.DB[this.modelName] || [];
console.log('models are:', models);

return models.find((model) => comparison(model, options, keys, 0));
},
insert(options) { // NOTE: what if there is same id?
const models = targetNamespace.MemServer.DB[this.modelName] || [];

// TODO: auto-increment ids
const defaultAttributes = this.attributes.reduce((result, attribute) => {
// TODO: enable functions
result[attribute] = this[attribute];
}, {});

const targetAttributes = Object.assign(defaultAttributes, options);

models.push(targetAttributes);
},
bulkInsert(count, options) {
return Array.from({ length: count }).map(() => this.insert(options));
},
update(record) {
const targetRecord = record.id ? this.find(record.id) : this.findBy({ uuid: record.uuid });

if (!targetRecord) {
throw new Error('[MemServer] $Model.update(record) requires id or uuid primary key to update a record');
}

const targetIndex = models.indexOf(targetRecord);

targetNamespace.MemServer.DB[this.modelName][targetIndex] = Object.assign(targetRecord, record);

return targetNamespace.MemServer.DB[this.modelName][targetIndex];
},
bulkUpdate() {

},
destroy(record) {
const models = targetNamespace.MemServer.DB[this.modelName];

if (models.length === 0) {
throw new Error(`[MemServer] ${this.modelName} has no records in the database to remove`);
}

const targetRecord = record.id ? this.find(record.id) : this.findBy({ uuid: record.uuid });

if (!targetRecord) {
throw new Error('[MemServer] $Model.destroy(record) requires id or uuid primary key to destroy a record');
}

const targetIndex = models.indexOf(targetRecord);

targetNamespace.MemServer.DB[this.modelName] = models.splice(targetIndex, 1);
},
bulkDestroy() {

},
serialize(objectOrArray) {

targetNamespace.MemServer.DB[this.modelName][targetIndex] = Object.assign(targetRecord, record);

return targetNamespace.MemServer.DB[this.modelName][targetIndex];
},
bulkUpdate() {

},
destroy(record) {
const models = targetNamespace.MemServer.DB[this.modelName];

if (models.length === 0) {
throw new Error(`[MemServer] ${this.modelName} has no records in the database to remove`);
}

const targetRecord = record.id ? this.find(record.id) : this.findBy({ uuid: record.uuid });

if (!targetRecord) {
throw new Error('[MemServer] $Model.destroy(record) requires id or uuid primary key to destroy a record');
}

const targetIndex = models.indexOf(targetRecord);

targetNamespace.MemServer.DB[this.modelName] = models.splice(targetIndex, 1);
},
bulkDestroy() {

},
serialize(objectOrArray) {

}
}, options);
}

// NOTE: if records were ordered by ID, then there could be performance benefit
Expand Down
17 changes: 17 additions & 0 deletions lib/mem-server/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export function generateUUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
const r = Math.random()*16|0, v = c === 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}

// export function getModelPrimaryKey(models) {
// if (!models.length) {
// return false;
// }
//
//
// // take random 3 elements from the array
// // check if all of them has id, otherwise getModelPrimaryKey is uuid, check they have uuid
// // models.
// }
79 changes: 48 additions & 31 deletions test/mem-server.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// const assert = require('chai').assert;
const assert = require('assert');
const fs = require('fs');
const rimraf = require('rimraf');
Expand Down Expand Up @@ -37,42 +36,60 @@ describe('MemServer', function() {

fs.mkdirSync(`./memserver`);
fs.mkdirSync(`./memserver/models`);
// fs.writeFileSync(`${process.cwd()}/memserver/server.js`, 'export default function(Models) {}');

assert.throws(() => require('../index.js'), (err) => {
return (err instanceof Error) &&
/\/memserver\/server.js doesn't exist for this directory!/.test(err);
});
});

// it('exports not yet started MemServer with right functions, registered Models and empty DB', () => {
// this.timeout(5000);
//
// fs.mkdirSync(`./memserver`);
// fs.mkdirSync(`./memserver/models`);
// // fs.writeFileSync(`${process.cwd()}/memserver/server.js`, 'export default function(Models) {}');
// fs.writeFileSync(`${process.cwd()}/memserver/server.js`, 'export default function(Models) {}');
//
// const MemServer = require('../index.js');
//
// assert.equal(MemServer.DB, {});
// assert.equal(Object.keys(MemS))
// });
});
it('exports a MemServer with right functions and empty DB when there is no model', function() {
this.timeout(5000);

fs.mkdirSync(`./memserver`);
fs.mkdirSync(`./memserver/models`);
fs.writeFileSync(`${process.cwd()}/memserver/server.js`, 'export default function(Models) {}');

const MemServer = require('../index.js');

assert.deepEqual(MemServer.DB, {});
assert.deepEqual(MemServer.Pretender, {});
assert.deepEqual(Object.keys(MemServer), ['DB', 'Pretender', 'Models', 'start', 'shutdown']);
assert.deepEqual(MemServer.Models, {});
});

it('exports a MemServer with right functions and empty DB and models', function() {
this.timeout(5000);

const modelFileContent = `import Model from '${process.cwd()}/lib/mem-server/model';
// it('can be started with default options', () => {
//
// });
//
// it('can be started with different options', () => {
//
// });
//
// it('can be shut down', () => {
//
// });
//
// it('can be shut down and started again with correct state', () => {
//
// });
export default Model({});`;

fs.mkdirSync(`./memserver`);
fs.mkdirSync(`./memserver/models`);
fs.writeFileSync(`${process.cwd()}/memserver/models/photo.js`, modelFileContent);
fs.writeFileSync(`${process.cwd()}/memserver/models/user.js`, modelFileContent);
fs.writeFileSync(`${process.cwd()}/memserver/models/photo-comment.js`, modelFileContent);
fs.writeFileSync(`${process.cwd()}/memserver/server.js`, 'export default function(Models) {}');

Object.keys(require.cache).forEach((key) => delete require.cache[key]);

const MemServer = require('../index.js');
const models = Object.keys(MemServer.Models);

assert.deepEqual(MemServer.DB, {});
assert.deepEqual(MemServer.Pretender, {});
assert.deepEqual(Object.keys(MemServer), ['DB', 'Pretender', 'Models', 'start', 'shutdown']);
assert.deepEqual(models, ['PhotoComment', 'Photo', 'User']);
models.forEach((modelName) => {
const model = MemServer.Models[modelName];

assert.equal(model.modelName, modelName);
assert.deepEqual(Object.keys(MemServer.Models[modelName]), [
'modelName', 'primaryKey', 'attributes', 'find', 'findAll', 'findBy', 'insert', 'bulkInsert', 'update',
'bulkUpdate', 'destroy', 'bulkDestroy', 'serialize'
]);
});
});
});
});
Loading

0 comments on commit 685fc7d

Please sign in to comment.