The SQL ORM aims to provide a simple library for common tasks when querying databases in JavaScript, and forming relations between these objects, taking a lot of ideas from the the [Data Mapper Pattern](http://en.wikipedia.org/wiki/Data_mapper_pattern).
The Strapi SQL ORM doesn't force you to use any specific validation scheme, provides flexible and efficient relation/nested-relation loading, and first class transaction support.
It's a lean Object Relational Mapper, allowing you to drop down to the [raw interface](./raw/index.html) whenever you need a custom query that doesn't quite fit with the stock conventions.
### Update a record with a one-to-one/one-to-many relationship
This is exactly the same as update a record without relationship.
```js
User.forge({
id: 123
})
.save({
'sponsor': 756
}, {path: true})
.then(function (model) {
return model.fetch({
withRelated: 'sponsor'
});
})
.then(function (model) {
console.log(model.toJSON());
})
.catch(function(err) {
reject(err);
});
```
The `console.log()` will print out:
```js
{
"id": 123,
"firstname": "John",
"lastname": "Does",
"age": 40,
"sponsor": {
"id": 756,
"firstname": "Martin",
"lastname": "Terry",
"age": 37
}
}
```
### Update a record with a many-to-many relationship
This is also exactly the same as update a record without relationship. However, there are two cases:
- Add new relationship(s) to a record
- Remove current(s) relationship(s) to the record
#### Add new relationship(s) to a record
```js
const friend3 = User.forge({id: 3});
User.forge({
id: 123
})
.friends()
.attach([friend3])
.then(function (model) {
return model.fetch({
withRelated: 'friends'
});
})
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.log(err);
});
```
The `console.log()` will print out:
```js
{
"id": 123,
"firstname": "John",
"lastname": "Doe",
"age": 20,
"friends": [{
"id": 1,
"firstname": "Peter",
"lastname": "Arrow",
"age": 53
}, {
"id": 2,
"firstname": "Andrea",
"lastname": "Nelson",
"age": 32
}, {
"id": 3,
"firstname": "Paul",
"lastname": "Thomas",
"age": 78
}]
}
```
#### Remove current(s) relationship(s) to a record
```js
const friend2 = User.forge({id: 2});
const friend3 = User.forge({id: 3});
User.forge({
id: 123
})
.friends()
.detach([friend2, friend3])
.then(function (model) {
return model.fetch({
withRelated: 'friends'
});
})
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.log(err);
});
```
The `console.log()` will print out:
```js
{
"id": 123,
"firstname": "John",
"lastname": "Doe",
"age": 20,
"friends": [{
"id": 1,
"firstname": "Peter",
"lastname": "Arrow",
"age": 53
}]
}
```
### Delete a record
```js
User.forge({
id: 123
})
.destroy()
.then(function (model) {
console.log(model.toJSON());
})
.catch(function(err) {
console.log(err);
});
```
The `console.log()` will print out:
```js
null
```
## Query options
### raw
```js
User.forge({
id: 123
})
.query(function (qb) {
qb.offset(0).limit(10);
}))
.fetch()
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.log(err);
})
```
### count
Count the entries for a query:
```js
User.forge()
.where({
'age': 20
})
.count()
.then(function (count) {
console.log(count);
})
.catch(function (err) {
console.log(err);
})
```
### where
Adds a `where` clause to the query:
```js
User.forge()
.where({
'firstname': 'John',
'age': 20
})
.fetch()
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.log(err);
});
```
### orderBy
Adds an `orderBy` clause to the query.
Using the object syntax:
```js
User.forge()
.query({
'orderBy': 'firstname'
})
.fetch()
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.log(err);
});
```
This syntax doesn't allow to update `ASC` / `DESC` parameter. To do so, you have to use the function syntax below:
```js
User.forge()
.query(function (qb) {
qb.orderBy('firstname', 'desc');
}))
.fetch()
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.log(err);
});
```
### groupBy
Adds an `groupBy` clause to the query:
```js
User.forge()
.query({
'groupBy': 'age'
})
.fetch()
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.log(err);
});
```
### limit
Adds an `limit` clause to the query:
```js
User.forge()
.query({
'limit': 20
})
.fetch()
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.log(err);
});
```
### offset
Adds an `offset` clause to the query:
```js
User.forge()
.query({
'offset': 10
})
.fetch()
.then(function (model) {
console.log(model.toJSON());
})
.catch(function (err) {
console.log(err);
});
```
## Lifecycle events
Lifecycle callbacks are functions you can define to run at certain times in a query. They are hooks that you can tap into in order to change data. Strapi exposes a handful of lifecycle callbacks by default.
Lifecycle events must be placed in your JavaScript file of your models.
### Common callbacks
#### beforeSave
Fired before an `insert` or `update` query. A promise may be returned from the event handler for async behavior. Throwing an exception from the handler will cancel the save.
Code:
```js
beforeSave: (model, attrs, options) => {
return new Promise();
},
```
Parameters:
-`model`: The model firing the event.
-`attrs`: Attributes that will be inserted or updated.
-`options`: Options object passed to `save`.
Returns: Promise.
#### afterSave
Fired after an `insert` or `update` query.
Code:
```js
afterSave: (model, response, options) => {
return new Promise();
},
```
Parameters:
-`model`: The model firing the event.
-`response`: The database response.
-`options`: Options object passed to `save`.
Returns: Promise.
### Callbacks on fetch
#### beforeFetch
Fired before a `fetch` operation. A promise may be returned from the event handler for async behavior.
Code:
```js
beforeFetch: (model, columns, options) => {
return new Promise();
},
```
Parameters:
-`model`: The model firing the event.
-`columns`: The columns to be retrieved by the query.
-`options`: Options object passed to `fetch`.
Returns: Promise.
#### afterFetch
Fired after a `fetch` operation. A promise may be returned from the event handler for async behavior.
Code:
```js
afterFetch: (model, response, options) => {
return new Promise();
},
```
Parameters:
-`model`: The model firing the event.
-`response`: SQL query response.
-`options`: Options object passed to `fetch`.
Returns: Promise. *If the handler returns a promise, `fetch` will wait for it to be resolved.*
### Callbacks on create
#### beforeCreate
Fired before `insert` query. A promise may be returned from the event handler for async behavior. Throwing an exception from the handler will cancel the save operation.
Code:
```js
beforeCreate: (model, attrs, options) => {
return new Promise();
},
```
Parameters:
-`model`: The model firing the event.
-`attrs`: Attributes that will be inserted.
-`options`: Options object passed to `save`.
Returns: Promise.
#### afterCreate
Fired after an `insert` query.
Code:
```js
afterCreate: (model, attrs, options) => {
return new Promise();
},
```
Parameters:
-`model`: The model firing the event.
-`attrs`: Attributes inserted.
-`options`: Options object passed to `save`.
Returns: Promise.
### Callbacks on update
#### beforeUpdate
Fired before an `update` query. A promise may be returned from the event handler for async behavior. Throwing an exception from the handler will cancel the save operation.
Code:
```js
beforeUpdate: (model, attrs, options) => {
return new Promise();
},
```
Parameters:
-`model`: The model firing the event.
-`attrs`: Attributes that will be updated.
-`options`: Options object passed to `save`.
Returns: Promise.
#### afterUpdate
Fired after an `update` query.
Code:
```js
afterUpdate: (model, attrs, options) => {
return new Promise();
},
```
Parameters:
-`model`: The model firing the event.
-`attrs`: Attributes updated.
-`options`: Options object passed to `save`.
Returns: Promise.
### Callbacks on destroy
#### beforeDestroy
Fired before a `delete` query. A promise may be returned from the event handler for async behavior. Throwing an exception from the handler will reject the promise and cancel the deletion.
Code:
```js
beforeDestroy: (model, attrs, options) => {
return new Promise();
},
```
Parameters:
-`model`: The model firing the event.
-`attrs`: Attributes that will be destroyed.
-`options`: Options object passed to `save`.
Returns: Promise.
#### afterDestroy
Fired before a `delete` query. A promise may be returned from the event handler for async behavior.