Skip to content

Commit

Permalink
$Model.insert() final implementation with tests
Browse files Browse the repository at this point in the history
  • Loading branch information
izelnakri committed Oct 25, 2017
1 parent f72416f commit 46c9820
Show file tree
Hide file tree
Showing 8 changed files with 407 additions and 57 deletions.
19 changes: 3 additions & 16 deletions lib/mem-server.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import fs from 'fs';
import chalk from 'chalk';
import stringUtils from 'ember-cli-string-utils';
import { primaryKeyTypeSafetyCheck } from './mem-server/utils';

const inflect = require('i')(); // NOTE: make this ES6 import
const ENVIRONMENT_IS_NODE = typeof global === 'object';
Expand Down Expand Up @@ -124,7 +125,6 @@ function resetDatabase(models) {
}, {});
}


function getModelPrimaryKey(model, existingPrimaryKeyType, modelName) {
if (!existingPrimaryKeyType) {
const primaryKey = model.id || model.uuid;
Expand All @@ -135,23 +135,10 @@ function getModelPrimaryKey(model, existingPrimaryKeyType, modelName) {

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 id: ${primaryKey} with ${primaryKeyType} type`));
} else if (targetPrimaryKeyType === 'uuid' && (primaryKeyType !== 'string')) {
throw new Error(chalk.red(`MemServer ${modelName} model primaryKeyType is 'uuid'. Instead you've tried to enter uuid: ${primaryKey} with ${primaryKeyType} type`));
return primaryKeyTypeSafetyCheck(existingPrimaryKeyType, primaryKey, modelName);
}

return targetPrimaryKeyType;
return primaryKeyTypeSafetyCheck(existingPrimaryKeyType, model[existingPrimaryKeyType], modelName);
}

// TODO: BUILD A CLI
52 changes: 35 additions & 17 deletions lib/mem-server/model.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import util from 'util';
import chalk from 'chalk';
import { generateUUID } from './utils';
import { primaryKeyTypeSafetyCheck, generateUUID } from './utils';

const targetNamespace = typeof global === 'object' ? global : window;

Expand All @@ -9,6 +10,11 @@ export default function(options) {
primaryKey: '',
defaultAttributes: {},
attributes: [],
count() {
const models = targetNamespace.MemServer.DB[this.modelName] || [];

return models.length;
},
find(param) {
if (!param) {
throw new Error(chalk.red(`MemServer ${this.modelName}.find(id) cannot be called without a valid id`));
Expand All @@ -32,6 +38,7 @@ export default function(options) {
if (!options) {
throw new Error(chalk.red(`MemServer ${this.modelName}.findBy(id) cannot be called without a parameter`));
}

const keys = Object.keys(options);
const models = targetNamespace.MemServer.DB[this.modelName] || [];

Expand All @@ -47,7 +54,7 @@ export default function(options) {

return models.filter((model) => comparison(model, options, keys, 0));
},
insert(options) { // NOTE: what if there is same id?
insert(options) {
const models = targetNamespace.MemServer.DB[this.modelName] || [];
const defaultAttributes = this.attributes.reduce((result, attribute) => {
if (attribute === this.primaryKey) {
Expand All @@ -62,10 +69,19 @@ export default function(options) {

return result;
}, {});
const target = Object.assign(defaultAttributes, options);

primaryKeyTypeSafetyCheck(this.primaryKey, target[this.primaryKey], this.modelName);

const existingRecord = target.id ? this.find(target.id) : this.findBy({ uuid: target.uuid });

const targetAttributes = Object.assign(defaultAttributes, options);
if (existingRecord) {
throw new Error(chalk.red(`[MemServer] ${this.modelName} ${this.primaryKey} ${target[this.primaryKey]} already exists in the database! ${this.modelName}.insert(${util.inspect(options)}) fails`));
}

models.push(target);

models.push(targetAttributes);
return target;
},
bulkInsert(count, options) {
return Array.from({ length: count }).map(() => this.insert(options));
Expand All @@ -74,7 +90,7 @@ export default function(options) {
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');
throw new Error(chalk.red(`[MemServer] ${this.modelName}.update(record) requires id or uuid primary key to update a record`));
}

const targetIndex = models.indexOf(targetRecord);
Expand All @@ -83,27 +99,28 @@ export default function(options) {

return targetNamespace.MemServer.DB[this.modelName][targetIndex];
},
bulkUpdate() {
bulkUpdate(records) {
const targetRecord = record.id ? this.find(record.id) : this.findBy({ uuid: record.uuid });

},
delete(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`);
throw new Error(chalk.red(`[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, you have provided this parameter: ${record}');
throw new Error(chalk.red(`[MemServer] ${this.modelName}.destroy(record) requires id or uuid primary key to destroy a record, you have provided this parameter: ${record}`));
}

const targetIndex = models.indexOf(targetRecord);

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

},
serialize(objectOrArray) {
Expand All @@ -113,15 +130,18 @@ export default function(options) {
}

function incrementId(Model) {
const ids = targetNamespace.MemServer.DB[Model.modelName].map((model) => model.id);
const ids = targetNamespace.MemServer.DB[Model.modelName];

if (ids === []) {
if (ids.length === 0) {
return 1;
}

return ids.sort((a, b) => a - b).find((id, index, array) => {
return index === array.length - 1 ? true : id + 1 !== array[index + 1];
}) + 1;
const lastIdInSequence = ids
.map((model) => model.id)
.sort((a, b) => a - b)
.find((id, index, array) => index === array.length - 1 ? true : id + 1 !== array[index + 1]);

return lastIdInSequence + 1;
}

// NOTE: if records were ordered by ID, then there could be performance benefit
Expand All @@ -130,9 +150,7 @@ function comparison(model, options, keys, index=0) {

if (keys.length === index) {
return model[key] === options[key];
}

if (model[key] === options[key]) {
} else if (model[key] === options[key]) {
return comparison(model, options, keys, index + 1)
}

Expand Down
23 changes: 13 additions & 10 deletions lib/mem-server/utils.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import chalk from 'chalk';

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.
// }
export function primaryKeyTypeSafetyCheck(targetPrimaryKeyType, primaryKey, modelName) {
const primaryKeyType = typeof primaryKey;

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

return targetPrimaryKeyType;
}
4 changes: 2 additions & 2 deletions test/mem-server.fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ describe('MemServer fixture constraint feature', function() {

assert.throws(() => MemServer.start(), (err) => {
return (err instanceof Error) &&
/MemServer Photo model primaryKeyType is 'id'. Instead you've tried to enter id: 2 with string type/.test(err);
/MemServer Photo model primaryKey type is 'id'. Instead you've tried to enter id: 2 with string type/.test(err);
});

assert.deepEqual(MemServer.Pretender, {});
Expand Down Expand Up @@ -226,7 +226,7 @@ describe('MemServer fixture constraint feature', function() {

assert.throws(() => MemServer.start(), (err) => {
return (err instanceof Error) &&
/MemServer PhotoComment model primaryKeyType is 'uuid'. Instead you've tried to enter uuid: 12 with number type/.test(err);
/MemServer PhotoComment model primaryKey type is 'uuid'. Instead you've tried to enter uuid: 12 with number type/.test(err);
});

assert.deepEqual(MemServer.Pretender, {});
Expand Down
5 changes: 3 additions & 2 deletions test/mem-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,9 @@ describe('MemServer', function() {

assert.equal(model.modelName, modelName);
assert.deepEqual(Object.keys(MemServer.Models[modelName]), [
'modelName', 'primaryKey', 'defaultAttributes', 'attributes', 'find', 'findBy', 'findAll',
'insert', 'bulkInsert', 'update', 'bulkUpdate', 'delete', 'bulkDelete', 'serialize'
'modelName', 'primaryKey', 'defaultAttributes', 'attributes', 'count', 'find', 'findBy',
'findAll', 'insert', 'bulkInsert', 'update', 'bulkUpdate', 'delete', 'bulkDelete',
'serialize'
]);
});
});
Expand Down
Empty file.
Loading

0 comments on commit 46c9820

Please sign in to comment.