Skip to content

Instantly share code, notes, and snippets.

@newhouse
Created December 13, 2017 23:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save newhouse/c3b052a3548396274210827c6be66875 to your computer and use it in GitHub Desktop.
Save newhouse/c3b052a3548396274210827c6be66875 to your computer and use it in GitHub Desktop.
Objection.js: inconsistent typing of 'date-time' Model props
'use strict';
const _ = require('lodash');
const objection = require('objection');
const Model = objection.Model;
const knex = require('knex')({
debug: false,
client: 'pg',
connection: 'INSERT CONNECTION STRING HERE',
pool: {
min: 2,
max: 2
}
});
Model.knex(knex);
/**************************************************
* ___ _ _
* | \ __ _| |_ __ _| |__ __ _ ___ ___
* | |) / _` | _/ _` | '_ \/ _` (_-</ -_)
* |___/\__,_|\__\__,_|_.__/\__,_/__/\___|
*
*/
const createTables = () => {
return knex.schema.createTableIfNotExists('parents', table => {
table.string('id', 4).notNullable();
table.timestamp('time').defaultTo(knex.fn.now());
table.primary(['id']);
})
.then(() => {
return knex.schema.createTableIfNotExists('children', table => {
table.string('id', 4).notNullable();
table.string('parent_id', 4).references('parents.id').onDelete('CASCADE').notNullable();
table.timestamp('time').defaultTo(knex.fn.now());
table.primary(['id']);
});
});
};
const dropTables = () => {
return knex.schema.dropTableIfExists('children')
.then(() => {
return knex.schema.dropTableIfExists('parents');
});
};
/**************************************************
* __ __ _ _
* | \/ |___ __| |___| |___
* | |\/| / _ \/ _` / -_) (_-<
* |_| |_\___/\__,_\___|_/__/
*
*/
class Parent extends Model {
static get tableName() {
return 'parents';
}
static get jsonSchema() {
return {
type: 'object',
required: ['id'],
properties: {
id: {
type: 'string',
maxLength: 4
},
time: {
type: 'string',
format: 'date-time'
}
}
};
}
static get relationMappings() {
return {
children: {
relation: Model.HasManyRelation,
modelClass: Child,
join: {
from: 'parents.id',
to: 'children.parent_id'
}
}
};
}
}
class Child extends Model {
static get tableName() {
return 'children';
}
static get jsonSchema() {
return {
type: 'object',
required: ['id', 'parent_id'],
properties: {
id: {
type: 'string',
maxLength: 4
},
parent_id: {
type: 'string',
maxLength: 4
},
time: {
type: 'string',
format: 'date-time'
}
}
};
}
}
// Let us know if things look weird.
function checkForNonString(things, where) {
if (things.constructor.name !== 'Array') {
things = [things];
}
let ok = true;
for (let i=0; i < things.length; i++) {
const thing = things[i];
if (typeof thing.time !== 'string') {
const msg = `** ${where}'s "time" is NOT a string:`;
console.log(msg);
// console.log({time: thing.time});
// throw new Error(msg);
ok = false;
break;
}
}
if (ok) {
console.log(`All good in ${where}`);
}
}
const PARENT_ID = 'P1';
const CHILD_ID_ONE = 'C1';
const CHILD_ID_TWO = 'C2';
// At no point am I using an object, just the String from it
const TIME = new Date().toISOString();
// OH MAN, HERE WE GO
return dropTables()
.then(() => {
return createTables();
})
.then(() => {
// Insert a Parent alone
return Parent
.query()
.insert({
id: PARENT_ID,
time: TIME
})
})
.then(parent => {
checkForNonString(parent, 'parent created by itself');
// Insert a Child alone
return Child
.query()
.insert({
id: CHILD_ID_ONE,
time: TIME,
parent_id: PARENT_ID
});
})
.then(child => {
checkForNonString(child, 'child created by itself');
// Delete it all to begin again
return Parent.query().delete();
})
.then(() => {
// Graph insert a Parent and a Child
return Parent
.query()
.insertGraph({
id: PARENT_ID,
time: TIME,
children: [
{
id: CHILD_ID_ONE,
time: TIME
}
]
})
.returning('*');
})
.then(parent => {
checkForNonString(parent, 'parent created during graph insert');
checkForNonString(parent.children, 'children created during graph insert');
// Directly query for a Parent using where
return Parent
.query()
.where({
id: PARENT_ID
})
.limit(1)
.first();
})
.then(parent => {
checkForNonString(parent, 'parent queried directly with where');
// Directly query for a Parent using findById
return Parent
.query()
.findById(PARENT_ID);
})
.then(parent => {
checkForNonString(parent, 'parent queried directly with findById');
// Eager query for some Children
return Parent
.query()
.eager('children')
.findById(PARENT_ID);
})
.then(parent => {
checkForNonString(parent, 'parent fetched having an eager');
checkForNonString(parent.children, 'children fetched via eager');
// Load it up from JSON - This is what led me to this bug
const childFromJson = Child.fromJson({
id: CHILD_ID_ONE,
parent_id: PARENT_ID,
time: TIME
});
checkForNonString(childFromJson, 'child created via fromJson');
return dropTables();
})
.catch(err => {
console.warn(err);
return dropTables();
})
.then(() => {
process.exit();
})
.catch(err => {
console.log(err);
process.exit();
});
{
"name": "objection-formatDatabaseJson",
"version": "0.0.1",
"description": "Objection 4-eva",
"main": "main.js",
"scripts": {
"start": "node ./app.js"
},
"engines": {
"node": "6.11.1"
},
"dependencies": {
"knex": "0.12.6",
"lodash": "latest",
"objection": "0.7.12",
"pg": "^6.1.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment