Skip to content

Commit

Permalink
New: syntax sugars like Model.first / Model.average
Browse files Browse the repository at this point in the history
  • Loading branch information
cyjake committed Dec 15, 2017
1 parent 0361de6 commit 983c064
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 41 deletions.
97 changes: 71 additions & 26 deletions lib/bone.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,17 @@ class Bone {
Object.defineProperties(this, {
raw: {
value: {},
writable: true,
writable: false,
enumerable: false
},
rawOriginal: {
value: {},
writable: true,
writable: false,
enumerable: false
},
rawMissing: {
value: new Set(),
writable: false,
enumerable: false
}
})
Expand All @@ -68,11 +73,13 @@ class Bone {
}

attribute(name, value) {
if (!(name in this.constructor.schema)) {
throw new Error(`${this.constructor.name} has no ${name} attribute`)
const { schema } = this.constructor
if (!(name in schema)) {
throw new Error(`${this.constructor.name} has no attribute called ${name}`)
}
const { column } = this.constructor.schema[name]
const { column } = schema[name]

if (this.rawMissing.has(column)) throw new Error(`Missing attribute ${name}`)
if (arguments.length > 1) {
this.raw[column] = value
} else {
Expand Down Expand Up @@ -148,6 +155,7 @@ class Bone {
*/
save() {
const { primaryKey } = this.constructor
if (this.rawMissing.has(primaryKey)) throw new Error('Missing primary key')
if (this[primaryKey] == null) {
return this.create().then(() => this)
} else if (this.attributeChanged(primaryKey)) {
Expand Down Expand Up @@ -190,7 +198,8 @@ class Bone {

// About LAST_INSERT_ID()
// - http://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_last-insert-id
const spell = new Spell(Model, sql => {
const spell = new Spell(Model, spell => {
const sql = spell.toSqlString()
debug(sql)
return new Promise((resolve, reject) => {
pool.query(sql, (err, results) => {
Expand Down Expand Up @@ -239,7 +248,8 @@ class Bone {
if (value != null) data[name] = value
}

const spell = new Spell(Model, sql => {
const spell = new Spell(Model, spell => {
const sql = spell.toSqlString()
debug(sql)
return new Promise((resolve, reject) => {
pool.query(sql, (err, results, fields) => {
Expand Down Expand Up @@ -527,45 +537,62 @@ class Bone {
return results
}

static instantiate(entry, table) {
static instantiate(entry) {
const instance = new this()
const raw = {}
const rawOriginal = {}
const { raw, rawOriginal, rawMissing } = instance

for (let name in this.schema) {
for (const name in this.schema) {
const { column, type } = this.schema[name]
const columnAs = table ? `${table}:${column}` : column
raw[column] = this.cast(entry[columnAs], type)
rawOriginal[column] = this.cast(entry[columnAs], type)
if (column in entry) {
// to make sure raw and rawOriginal hold two different objcets
raw[column] = this.cast(entry[column], type)
rawOriginal[column] = this.cast(entry[column], type)
} else {
rawMissing.add(column)
}
}

instance.raw = raw
instance.rawOriginal = rawOriginal

return instance
}

static get all() {
return this.find()
}

static get first() {
return this.findOne().$order(this.primaryKey)
}

static get last() {
return this.findOne().$order(this.primaryKey, 'desc')
}

static find(conditions, ...values) {
const { pool } = this
const spell = new Spell(this, sql => {
const spell = new Spell(this, spell => {
const sql = spell.toSqlString()
const nestTables = spell.dispatchable
debug(sql)
return new Promise((resolve, reject) => {
const nestTables = spell.dispatchable
pool.query({ sql, nestTables }, (err, results, fields) => {
if (err) reject(err)
else resolve(nestTables ? this.dispatch(spell, results, fields) : results)
})
})
})

const conditionsType = typeof conditions
if (Array.isArray(conditions) || conditionsType == 'number') {
spell.$where({ id: conditions })
}
// find({}, { offset: 1, limit: 1 })
if (typeof conditions == 'object' && values.length == 1 && typeof values[0] == 'object') {
else if (typeof conditions == 'object' && values.length == 1 && typeof values[0] == 'object') {
spell.$where(conditions)
for (const method of ['order', 'limit', 'offset', 'select']) {
const value = values[0][method]
if (value != null) spell[`$${method}`](value)
}
} else if (conditions) {
}
else if (conditions) {
spell.$where(conditions, ...values)
}

Expand Down Expand Up @@ -600,8 +627,24 @@ class Bone {
return this.find().$join(Model, conditions, ...values)
}

static count(conditions, ...values) {
return this.find(conditions, ...values).$count()
static count(name) {
return this.find().$count(name)
}

static average(name) {
return this.find().$average(name)
}

static minimum(name) {
return this.find().$minimum(name)
}

static maximum(name) {
return this.find().$maximum(name)
}

static sum(name) {
return this.find().$sum(name)
}

static create(values) {
Expand All @@ -611,7 +654,8 @@ class Bone {

static update(conditions, values) {
const { pool } = this
const spell = new Spell(this, sql => {
const spell = new Spell(this, spell => {
const sql = spell.toSqlString()
debug(sql)
return new Promise((resolve, reject) => {
pool.query(sql, (err, results) => {
Expand All @@ -635,7 +679,8 @@ class Bone {
forceDelete = forceDelete === true

if (forceDelete) {
const spell = new Spell(this, sql => {
const spell = new Spell(this, spell => {
const sql = spell.toSqlString()
debug(sql)
return new Promise((resolve, reject) => {
pool.query(sql, (err, results) => {
Expand Down
27 changes: 25 additions & 2 deletions lib/spell.js
Original file line number Diff line number Diff line change
Expand Up @@ -578,8 +578,7 @@ class Spell {
// `Model.findOne()` needs to edit the resolved results before returning it to user. Hence a intermediate resolver called `onresolve` is added. It gets copied when the spell is duplicated too.
let promise = new Promise(resolve => {
setImmediate(() => {
const { factory } = this
resolve(factory(this.toSqlString()))
resolve(this.factory.call(null, this))
})
})
const { onresolve } = this
Expand Down Expand Up @@ -683,6 +682,30 @@ class Spell {
return this
}

$average(name = '*') {
name = isIdentifier(name) ? name: '*'
this.attributes = new Set([`avg(${name}) as average`])
return this
}

$minimum(name = '*') {
name = isIdentifier(name) ? name: '*'
this.attributes = new Set([`min(${name}) as minimum`])
return this
}

$maximum(name = '*') {
name = isIdentifier(name) ? name: '*'
this.attributes = new Set([`max(${name}) as maximum`])
return this
}

$sum(name = '*') {
name = isIdentifier(name) ? name: '*'
this.attributes = new Set([`sum(${name}) as sum`])
return this
}

/**
* Example usage:
*
Expand Down
1 change: 1 addition & 0 deletions tests/dumpfile.sql
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ CREATE TABLE `books` (
`gmt_create` datetime NOT NULL,
`gmt_modified` datetime NOT NULL,
`name` varchar(1000) NOT NULL,
`price` decimal(10, 3) NOT NULL,
PRIMARY KEY (`isbn`)
);

Expand Down
Loading

0 comments on commit 983c064

Please sign in to comment.