Skip to content

Commit

Permalink
Merge pull request #24 from citycide/feat-create-return
Browse files Browse the repository at this point in the history
Make `create()` return the object
  • Loading branch information
Bo Lingen committed Feb 3, 2017
2 parents e707d64 + e90cdff commit 3f7f662
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 8 deletions.
7 changes: 6 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ insert will be ignored when violating this constraint.

> **Returns**
`Promise<Number>`: the number of objects created
`Promise<Object>`: the created object

> **Usage**
Expand All @@ -375,6 +375,11 @@ players.create({
id: 197397332,
username: 'xX420_sniperXx',
friends: ['xX420_kniferXx']
}).then(object => {
console.log(object)
// { id: 197397332,
// username: 'xX420_sniperXx',
// friends: ['xX420_kniferXx'] }
})
```

Expand Down
45 changes: 41 additions & 4 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,10 @@ export function isValidWhere (where) {
}

export function runQuery (instance, query, needResponse) {
let asString = query.toString()
let action = getQueryAction(asString)
if (util.isFunction(instance.verbose)) {
instance.verbose(query.toString())
instance.verbose(asString)
}

if (instance.isNative) {
Expand All @@ -83,14 +85,14 @@ export function runQuery (instance, query, needResponse) {
let response

if (needResponse) {
response = parseResponse(db.exec(query.toString()))
response = parseResponse(db.exec(asString))
if (query._sequence && query._sequence[0].method === 'hasTable') {
response = !!response.length
}
} else {
db.run(query.toString())
db.run(asString)

if (util.isOneOf(['insert', 'update', 'delete'], query._method)) {
if (util.isOneOf(['insert', 'update', 'delete'], action)) {
response = db.getRowsModified()
}
}
Expand All @@ -100,3 +102,38 @@ export function runQuery (instance, query, needResponse) {
return response
})
}

export function findLastObject (model, object) {
let { key, hasIncrements } = findKey(model.schema)

if (!key && !hasIncrements) return

let query = hasIncrements
? model.ctx.knex('sqlite_sequence').first('seq').where({ name: model.name })
: model.ctx.knex(model.name).first().where({ [key]: object[key] })

return runQuery(model.ctx, query, true)
.then(res => hasIncrements ? model.findOne({ [key]: res.seq }) : res)
}

function findKey (schema) {
let key = ''
let hasIncrements = false
for (let name in schema) {
if (!schema.hasOwnProperty(name)) continue
let props = schema[name]
if (props === 'increments' || props.type === 'increments') {
key = name
hasIncrements = true
break
} else if (props.primary || props.unique) {
key = name
}
}

return { key, hasIncrements }
}

function getQueryAction (str) {
return str.split(' ', 1)[0].toLowerCase()
}
3 changes: 2 additions & 1 deletion src/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export default class Model {
)

return helpers.runQuery(this.ctx, query)
.then(() => helpers.findLastObject(this, object))
.then(res => res || this.findOne(object))
}

find (column, criteria, options = {}) {
Expand Down Expand Up @@ -91,7 +93,6 @@ export default class Model {
.then(existing => {
if (existing) return existing
return this.create({ ...criteria, ...creation })
.then(() => this.findOne(criteria))
})
}

Expand Down
38 changes: 38 additions & 0 deletions tests/find-or-create.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Trilogy from '../dist/trilogy'

import test from 'ava'
import { remove } from 'fs-jetpack'
import { join, basename } from 'path'

const filePath = join(__dirname, `${basename(__filename, '.js')}.db`)
const db = new Trilogy(filePath)

const makeInput = date => ({ name: 'Overwatch', last_played: date, genre: 'FPS' })

test.before(async () => {
await db.model('games', {
name: { type: String, primary: true },
last_played: Date,
genre: String
})
})

test.after.always('remove test database file', () => {
return db.close().then(() => remove(filePath))
})

test('creates missing objects or returns an existing one', async t => {
t.is(await db.count('games', { genre: 'FPS' }), 0)

let first = makeInput(new Date('Jan 31, 2017'))
let fresh = await db.findOrCreate('games', first)
t.is(await db.count('games', { genre: 'FPS' }), 1)

let duplicate = makeInput(new Date('Feb 2, 2017'))
let existing = await db.findOrCreate('games', duplicate)
t.deepEqual(fresh, existing)
t.is(await db.count('games', { genre: 'FPS' }), 1)

t.is(fresh.last_played, existing.last_played)
})

4 changes: 2 additions & 2 deletions tests/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ test('defines a model with a uniquely constrained property', async t => {

let object = { name: 'coke', flavor: 'awesome' }
await db.create('sodas', object)
await db.create('sodas', object)

let duplicate = await db.create('sodas', object)
t.is(duplicate, 0)
t.is(await db.count('sodas', { name: 'coke' }), 1)
})

0 comments on commit 3f7f662

Please sign in to comment.