Bone

Bone

The base class that provides Object-relational mapping. This class is never intended to be used directly. We need to create models that extends from Bone. Most of the query features of Bone is implemented by Spell such as Spell#$group and Spell#$join. With Bone, you can create models like this:

class Post extends Bone {
  static initialize() {
    this.hasMany('comments')
    this.belongsTo('author', { className: 'User' })
    this.attribute('extra', { type: JSON })
  }
}

And then query posts by lots of means:

Post.first
Post.where('title = ? && authorId = ?', 'Leah', 42)
Post.include('comments').group('posts.id').count('comments.*').order('count')

Constructor

new Bone(dataValues)

Create an instance of Bone. Accepts initial data values.

Properties:
Name Type Description
#raw Object
#rawSaved Object
#rawPrevious Object
#rawUnset Set
isNewRecord Boolean
Parameters:
Name Type Description
dataValues Object
Example:
const post = new Post()
const post = new Post({ title: 'Leah' })

Members

(static) all

An alias of Bone.find without any conditions. To get all records in database, including those ones marked deleted, use spell#$unscoped. This getter returns all records by querying them at once, which can be inefficient if table contains loads of data. It is recommended to consume data by spell#$batch.

Example
Post.all           // fetches at once.
Post.all.unscoped  // fetches (soft) deleted records too.
Post.all.batch()   // fetches records 1000 by 1000s.

(static) pool

get the connection pool of the driver

(static) primaryColumn :string

The primary column of the model, in snake_case, usually.

(static) primaryKey :string

The primary key of the model, in camelCase.

Methods

(static) attribute(name, meta)

Override attribute metadata. Currently only type is needed to be overriden with this method.

Parameters:
Name Type Description
name string
meta Object
Example:
class Post extends Bone {
  static initialize() {
    Post.attribute('extra', { type: JSON })
  }
}

(static) belongsTo(name, optsopt)

Set a belongsTo association to another model. The model is inferred by opts.className or the association name by default.

Parameters:
Name Type Attributes Description
name string
opts Object <optional>
Name Type Attributes Description
className string <optional>
foreignKey string <optional>

(static) create(values) → {Spell}

Insert data into database, or update corresponding records if primary key exists. This method use Bone#create as the underlying method. Hence calling Post.create({}) is basically the same as new Post({}).save().

Parameters:
Name Type Description
values Object
Returns:
Type:
Spell
Example:
Post.create({ title: 'Leah' })
Post.create({ id: 1, title: 'Diablo III', createdAt: new Date(2012, 4, 15) })

(static) find(conditions, …values) → {Spell}

Start a find query by creating and returning an instance of Spell. The conditions and values are handed over to spell#$where.

Parameters:
Name Type Attributes Description
conditions string | Object
values * <repeatable>
Returns:
Type:
Spell

(static) findOne(conditions, …values) → {Spell}

Start a find query like Bone.find with results limit to one, hence only one instance gets returned.

Parameters:
Name Type Attributes Description
conditions string | Object
values * <repeatable>
Returns:
Type:
Spell
Example:
Post.findOne()
Post.findOne('title = ?', ['Leah', 'Deckard Cain'])
Post.findOne().unscoped

(static) hasAttribute(name) → {boolean}

Model.hasAttribute(name)

Parameters:
Name Type Description
name string
Returns:
Type:
boolean

(static) hasMany(name, optsopt)

Set a hasMany association to another model. The model is inferred by opts.className or the association name by default.

Parameters:
Name Type Attributes Description
name string
opts Object <optional>
Name Type Attributes Description
className string <optional>
foreignKey string <optional>

(static) hasOne(name, optsopt)

Set a hasOne association to another model. The model is inferred by opts.className or the association name by default.

Parameters:
Name Type Attributes Description
name string
opts Object <optional>
Name Type Attributes Description
className string <optional>
foreignKey string <optional>

(static) include(…names)

Start a join query by including associations by name. The associations should be predefined in model's static describe() method. See Bone.belongsTo, Bone.hasMany, and Bone.hasOne for more information.

Parameters:
Name Type Attributes Description
names string <repeatable>

association names defined in Bone.initialize

Example:
class Post extends Bone {
  static initialize() {
    this.hasMany('comments')
    this.belongsTo('author')
  }
}
Post.include('comments')
Post.include('author', 'comments')

(static) initialize()

Override this method to setup associations, rename attributes, etc.

Example:
class Post extends Bone {
  static didLoad() {
    this.belongsTo('author', { className: 'User' })
    this.renameAttribute('content', 'body')
  }
}

(static) loadAttribute(name)

Load attribute definition to merge default getter/setter and custom descriptor on prototype

Parameters:
Name Type Description
name string

attribute name

(static) remove(conditions, forceDelete) → {Spell}

Remove any record that matches conditions.

  • If forceDelete is true, DELETE records from database permanently.
  • If not, update deletedAt attribute with current date.
  • If forceDelete isn't true and deleteAt isn't around, throw an Error.
Parameters:
Name Type Default Description
conditions Object
forceDelete boolean false
Returns:
Type:
Spell
Example:
Post.remove({ title: 'Leah' })         // mark Post { title: 'Leah' } as deleted
Post.remove({ title: 'Leah' }, true)   // delete Post { title: 'Leah' }
Post.remove({}, true)                  // delete all data of posts

(static) renameAttribute(originalName, newName)

Rename attribute. Since Bone manages a separate set of names called attributes instead of using the raw columns, we can rename the attribute names, which is transformed from the column names by convention, to whatever name we fancy.

Parameters:
Name Type Description
originalName string
newName string

(static) restore(conditions, optsnullable) → {Spell}

restore rows

Parameters:
Name Type Attributes Description
conditions Object

query conditions

opts Object <nullable>

query options

Returns:
Type:
Spell

(static) update(conditions, values) → {Spell}

Update any record that matches conditions.

Parameters:
Name Type Description
conditions Object
values Object
Returns:
Type:
Spell
Example:
Post.update({ title: 'Leah' }, { title: 'Diablo III' })

(static) upsert(values, options)

Model.upsert Returns number of affectedRows.

Parameters:
Name Type Description
values object
options object
Returns:

number of affectedRows.

_clone(target)

clone instance

Parameters:
Name Type Description
target Bone

attribute(name, valueopt) → {*}

Get or set attribute value by name. This method is quite similiar to jQuery.attr(). If the attribute isn't selected when queried from database, an error will be thrown when accessing it.


    const post = Post.select('title').first

This is the underlying method of attribute getter/setters:

Object.defineProperty(Post.prototype, 'title', {
    get: function() { return this.attribute('title') },
    set: function(value) { return this.attribute('title', value) }
})

These getters and setters are automatically generated while Bone.describe is called.

Parameters:
Name Type Attributes Description
name string

attribute name

value * <optional>

attribute value

Returns:
Type:
*
Example:
.attribute('title')                 // get the value of title
.attribute('title', 'New Post')  // set the value of title to 'New Post'

attributeChanged(name)

Deprecated:
  • {attributeChanged} is deprected, use Bone#changed instead Check if the value of attribute is changed or not (Bone#rawSaved).
Parameters:
Name Type Description
name string

attribute name

Example:
const post = await Post.findOne({ title: 'Leah' })
post.title = 'Deckard Cain'
post.attributeChanged('title')  // => true
post.title = 'Leah'
post.attributeChanged('title')  // => false

attributeWas(name)

Get the original value of attribute. If the attribute isn't selected in the first place, an error will be thrown when accessing it.

Parameters:
Name Type Description
name string

attribute name

Example:
const post = await Post.findOne({ title: 'Leah' })
post.title = 'Deckard Cain'
post.attributeWas('title')  // => 'Leah'

changed(name) → {boolean|Array.<string>}

attribute changed or not

Parameters:
Name Type Description
name string
Returns:
Type:
boolean | Array.<string>

changed or not | attribute name array

Example:
bone.changed('a');  // true
bone.changed();     // [ 'a', 'b' ]

changes(namenullable) → {Object.<string, Array>}

Parameters:
Name Type Attributes Description
name string <nullable>
Returns:
Type:
Object.<string, Array>

changed attributes comparing current values Bone.raw against persisted values Bone.rawSaved

Example:
bone.changes('a');  // => { a: [ 1, 2 ] }
bone.changes();     // => { a: [ 1, 2 ], b: [ true, false ] }

create() → {Bone}

Returns:
Type:
Bone

created instance

hasAttribute(name) → {boolean}

instance.hasAttribute(name)

Parameters:
Name Type Description
name string
Returns:
Type:
boolean

previousChanged(namenullable) → {string|Array.<string>}

Get previous attribute changes. Please be noted that Bone#changes is about the changes made after the record is saved, and Bone#previousChanges only returns the changes made before the record was previously saved.

previousChanges ➡️ [saved] ➡️ changes ➡️ [current]
Parameters:
Name Type Attributes Description
name string <nullable>
Returns:
Type:
string | Array.<string>

changed attribute(s)' name that compare(s) to previous persisted value(s): Bone.raw compares to Bone.rawPrevious

Example:
bone.previousChanges('a');  // => { a: [ 1, 2 ] }
bone.previousChanges();     // => { a: [ 1, 2 ], b: [ true, false ] }

previousChanges(namenullable) → {Object.<string, Array>}

Parameters:
Name Type Attributes Description
name string <nullable>
Returns:
Type:
Object.<string, Array>

changed values comparing current values Bone.raw against previous values Bone.rawPrevious

(async) remove(forceDelete, optsnullable) → {number}

Parameters:
Name Type Attributes Description
forceDelete boolean
opts Object <nullable>
Returns:
Type:
number

effected rows

(async) restore(querynullable) → {Bone}

restore data

Parameters:
Name Type Attributes Description
query Object <nullable>

options

Returns:
Type:
Bone

instance

save() → {Bone}

Save the changes to database. If the instance isn't persisted to database before, an INSERT query will be executed. Otherwise, an upsert-like query is chosen to make sure only one instance of the specified primaryKey is created. If the primaryKey is positive but unchanged, an UPDATE will be executed.

Returns:
Type:
Bone

saved model itself

Example:
new Post({ title: 'Leah' }).save()
// same as Post.create({ title: 'Leah' })

const post = Post.first
post.title = 'Decard Cain'
post.save()

toJSON() → {Object}

Gets called when JSON.stringify(instance) is invoked. Bone#toJSON might be called on descents of Bone that does not have attributes defined on them directly, hence for..in is preferred.

  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties
Returns:
Type:
Object
Example:
const post = await Post.first
post.toJSON()  // => { id: 1, ... }

toObject() → {Object}

This is the loyal twin of Bone#toJSON because when generating the result object, the raw values of attributes are used, instead of the values returned by custom getters (if any). Bone#toObject might be called on descents of Bone that does not have attributes defined on them directly, hence for..in is preferred.

  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/Enumerability_and_ownership_of_properties
Returns:
Type:
Object
Example:
const post = await Post.first
post.toObject()  // => { id: 1, ... }

update(changes, optionsnullable) → {number}

Persist changes on current instance back to database with UPDATE.

Parameters:
Name Type Attributes Description
changes Object
options Object <nullable>
Returns:
Type:
number

affected rows

upsert() → {number}

Look for current instance in the database, then:

  • If found, save the changes to existing one.
  • If not found, create a new record.

Returns number of affectedRows.

Returns:
Type:
number

util.inspect.custom() → {string}

Gets called when console.log(instance) is invoked.

Returns:
Type:
string
Example:
const post = await Post.first
post.inspect()  // => 'Post { "id": 1, ... }'

validate()

instance.validate()