Skip to content

Commit

Permalink
Merge pull request #10 from baethon/timestamps
Browse files Browse the repository at this point in the history
Timestamps (closes #10)
  • Loading branch information
radmen committed May 8, 2020
2 parents 25389fd + 89af160 commit c5c1696
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 1 deletion.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
},
"dependencies": {
"dataloader": "^2.0.0",
"lodash.flow": "^3.5.0",
"lodash.frompairs": "^4.0.1",
"lodash.snakecase": "^4.1.1",
"pluralize": "^8.0.0"
Expand Down
2 changes: 2 additions & 0 deletions src/kex.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const { KexError } = require('./errors')
/** @typedef { import('./model') } Model */
/** @typedef { import('./model').ModelOptions } ModelOptions */
/** @typedef { import('./model').KnexClientResolver } KnexClientResolver */
/** @typedef { import('./model').TimestampsOptions } TimestampsOptions */

/**
* @type {Object} ModelDefaultOptions
Expand All @@ -18,6 +19,7 @@ const { KexError } = require('./errors')
* @property {Object.<String,Scope>} [scopes]
* @property {Object.<String,Scope>} [globalScopes]
* @property {KnexClientResolver} [knexClientResolver]
* @property {Boolean|TimestampsOptions} [timestamps=false]
*/

/**
Expand Down
8 changes: 8 additions & 0 deletions src/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ const { KexError } = require('./errors')
* @return {KnexClient}
*/

/**
* @typedef {Object} TimestampsOptions
* @property {String} [deletedAtColumn=deleted_at]
* @property {String} [updatedAtColumn=updated_at]
*/

/**
* @typedef {Object} ModelOptions
* @property {String} [tableName]
Expand All @@ -25,12 +31,14 @@ const { KexError } = require('./errors')
* @property {Object.<String,Scope>} [globalScopes]
* @property {Object.<String,Relation>} [relations]
* @property {KnexClientResolver} [knexClientResolver]
* @property {Boolean|TimestampsOptions} [timestamps=false]
*/

/**
* @typedef {Object} ExtendOptions
* @property {String} methodName
* @property {Function} fn
* @property {Boolean} [force=false]
* @property {Boolean} [queryProxy=false] should the function
* be proxied to the QueryBuilder?
*/
Expand Down
3 changes: 2 additions & 1 deletion src/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ const builtinPlugins = [
require('./find'),
require('./first-or-fail'),
require('./soft-deletes'),
require('./include')
require('./include'),
require('./timestamps')
]

/**
Expand Down
61 changes: 61 additions & 0 deletions src/plugins/timestamps.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
const flow = require('lodash.flow')
const { isObject } = require('../utils')

const setDateField = (name) => item => ({
...item,
[name]: new Date()
})

/**
* @param {import('../model')} Model
*/
module.exports = (Model) => {
const { timestamps = false } = Model.options

if (!timestamps) {
return
}

const { QueryBuilder } = Model
const timestampsOptions = isObject(timestamps)
? timestamps
: {}

const {
createdAtColumn = 'created_at',
updatedAtColumn = 'updated_at'
} = timestampsOptions

const {
insert: insertMethod,
update: updateMethod
} = QueryBuilder.prototype

const setUpdatedAt = setDateField(updatedAtColumn)
const setCreatedAt = setDateField(createdAtColumn)

QueryBuilder.extend({
methodName: 'update',
force: true,
fn (values, returning) {
return updateMethod.call(this, setUpdatedAt(values), returning)
}
})

QueryBuilder.extend({
methodName: 'insert',
force: true,
fn (values, returning) {
const update = flow([
setUpdatedAt,
setCreatedAt
])

const newValues = Array.isArray(values)
? values.map(update)
: update(values)

return insertMethod.call(this, newValues, returning)
}
})
}
97 changes: 97 additions & 0 deletions tests/plugins/timestamps.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
const test = require('ava')
const sinon = require('sinon')
const setupDb = require('../setup-db')
const { equalQueries } = require('../assertions')
const { createKex } = require('../utils')

setupDb()

test.before(() => {
sinon.useFakeTimers({ now: new Date() })
})

test('disabled timestamps', t => {
const { knex } = t.context
const User = createKex(t).createModel('User')

equalQueries(t, knex.from('users').insert({ foo: 1 }), User.insert({ foo: 1 }))
equalQueries(t, knex.from('users').update({ foo: 1 }), User.query().update({ foo: 1 }))
})

test('insert | default columns', async t => {
const { knex } = t.context
const User = createKex(t).createModel('User', {
timestamps: true
})

const expected = knex.table('users').insert({
foo: 1,
updated_at: new Date(),
created_at: new Date()
})

equalQueries(t, expected, User.insert({ foo: 1 }))
})

test('insert | list of items', async t => {
const { knex } = t.context
const User = createKex(t).createModel('User', {
timestamps: true
})

const data = [
{ foo: 1 },
{ foo: 2 }
]

const expected = knex.table('users').insert(data.map(item => ({
...item,
updated_at: new Date(),
created_at: new Date()
})))

equalQueries(t, expected, User.insert(data))
})

test('insert | custom column name', async t => {
const { knex } = t.context
const User = createKex(t).createModel('User', {
timestamps: { createdAtColumn: 'createdAt', updatedAtColumn: 'updatedAt' }
})

const expected = knex.table('users').insert({
foo: 1,
updatedAt: new Date(),
createdAt: new Date()
})

equalQueries(t, expected, User.insert({ foo: 1 }))
})

test('update | default columns', async t => {
const { knex } = t.context
const User = createKex(t).createModel('User', {
timestamps: true
})

const expected = knex.table('users').update({
foo: 1,
updated_at: new Date()
})

equalQueries(t, expected, User.query().update({ foo: 1 }))
})

test('update | custom column name', async t => {
const { knex } = t.context
const User = createKex(t).createModel('User', {
timestamps: { createdAtColumn: 'createdAt', updatedAtColumn: 'updatedAt' }
})

const expected = knex.table('users').update({
foo: 1,
updatedAt: new Date()
})

equalQueries(t, expected, User.query().update({ foo: 1 }))
})
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2723,6 +2723,11 @@ lodash.flattendeep@^4.4.0:
resolved "https://registry.yarnpkg.com/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz#fb030917f86a3134e5bc9bec0d69e0013ddfedb2"
integrity sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=

lodash.flow@^3.5.0:
version "3.5.0"
resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a"
integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o=

lodash.frompairs@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/lodash.frompairs/-/lodash.frompairs-4.0.1.tgz#bc4e5207fa2757c136e573614e9664506b2b1bd2"
Expand Down

0 comments on commit c5c1696

Please sign in to comment.