mirror of
https://github.com/strapi/strapi.git
synced 2025-11-03 11:25:17 +00:00
Merge branch 'develop' of github.com:strapi/strapi into front/media-lib-loader
This commit is contained in:
commit
18ac81057b
@ -4,21 +4,18 @@
|
||||
|
||||
### Content Type's models
|
||||
|
||||
Models are a representation of the database's structure and life cycle. They are split into two separate files. A JavaScript file that contains the life cycle callbacks, and a JSON one that represents the data stored in the database and their format. The models also allow you to define the relationships between them.
|
||||
Models are a representation of the database's structure. They are split into two separate files. A JavaScript file that contains the model options (e.g: lifecycle hooks), and a JSON one that represents the data structure stored in the database.
|
||||
|
||||
**Path —** `./api/restaurant/models/Restaurant.js`.
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
beforeSave: (model, attrs, options) => {},
|
||||
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
afterSave: (model, attrs, options) => {},
|
||||
|
||||
// ... and more
|
||||
lifecycles: {
|
||||
// Called before an entry is created
|
||||
beforeCreate(data) {},
|
||||
// Called after an entry is created
|
||||
afterCreated(result) {},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
@ -894,69 +891,203 @@ xhr.send(
|
||||
|
||||
::::
|
||||
|
||||
## Life cycle callbacks
|
||||
## Lifecycle hooks
|
||||
|
||||
::: warning
|
||||
The life cycle functions are based on the ORM life cycle and not on the Strapi request.
|
||||
We are currently working on it to make it easier to use and understand.
|
||||
Please check [this issue](https://github.com/strapi/strapi/issues/1443) on GitHub.
|
||||
:::
|
||||
The lifecycle hooks are functions that get triggered when the Strapi [`queries`](../concepts/queries.md) are called. They will get triggered automatically when you manage your content in the Admin Panel or when you develop custom code using `queries`·
|
||||
|
||||
The following events are available by default:
|
||||
To configure a `ContentType` lifecycle hooks you can set a `lifecycles` key in the `{modelName}.js` file located at `./api/{apiName}/models/{modelName}.js` folder.
|
||||
|
||||
Callbacks on:
|
||||
### Available Lifecycle hooks
|
||||
|
||||
:::: tabs
|
||||
|
||||
::: tab save
|
||||
::: tab find
|
||||
|
||||
`save`
|
||||
**`beforeFind(params, populate)`**
|
||||
|
||||
- beforeSave
|
||||
- afterSave
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ----------------------------------- |
|
||||
| params | Object | Find params _(e.g: limit, filters)_ |
|
||||
|
||||
---
|
||||
|
||||
**`afterFind(results, params, populate)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| -------- | ------------- | -------------------------------------- |
|
||||
| results | Array{Object} | The results found for the `find` query |
|
||||
| params | Object | Find params _(e.g: limit, filters)_ |
|
||||
| populate | Array{string} | Populate specific relations |
|
||||
|
||||
:::
|
||||
|
||||
::: tab fetch
|
||||
::: tab findOne
|
||||
|
||||
`fetch`
|
||||
**`beforeFindOne(params, populate)`**
|
||||
|
||||
- beforeFetch
|
||||
- afterFetch
|
||||
_Parameters:_
|
||||
|
||||
::: tab fetchAll
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ---------------------------- |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
|
||||
`fetchAll`
|
||||
---
|
||||
|
||||
- beforeFetchAll
|
||||
- afterFetchAll
|
||||
**`afterFindOne(result, params, populate)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| -------- | ------------- | ----------------------------------------- |
|
||||
| result | Object | The results found for the `findOne` query |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
| populate | Array{string} | Populate specific relations |
|
||||
|
||||
:::
|
||||
|
||||
::: tab create
|
||||
|
||||
`create`
|
||||
**`beforeCreate(data)`**
|
||||
|
||||
- beforeCreate
|
||||
- afterCreate
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ------ | ---------------------------------------- |
|
||||
| data | Object | Input data to the entry was created with |
|
||||
|
||||
---
|
||||
|
||||
**`afterCreate(result, data)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ---------------------------------------- |
|
||||
| result | Object | Created entry |
|
||||
| data | Object | Input data to the entry was created with |
|
||||
|
||||
:::
|
||||
|
||||
::: tab update
|
||||
|
||||
`update`
|
||||
**`beforeUpdate(params, data)`**
|
||||
|
||||
- beforeUpdate
|
||||
- afterUpdate
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ---------------------------------------- |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
| data | Object | Input data to the entry was created with |
|
||||
|
||||
---
|
||||
|
||||
**`afterUpdate(result, params, data)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ---------------------------------------- |
|
||||
| result | Object | Updated entry |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
| data | Object | Input data to the entry was created with |
|
||||
|
||||
:::
|
||||
|
||||
::: tab destroy
|
||||
::: tab delete
|
||||
|
||||
`destroy`
|
||||
**`beforeDeleted(params)`**
|
||||
|
||||
- beforeDestroy
|
||||
- afterDestroy
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ---------------------------- |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
|
||||
---
|
||||
|
||||
**`afterDeleted(result, params)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ---------------------------- |
|
||||
| result | Object | Deleted entry |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
|
||||
:::
|
||||
|
||||
::: tab count
|
||||
|
||||
**`beforeCount(params)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ---------------------------- |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
|
||||
---
|
||||
|
||||
**`afterCount(result, params)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------- | ---------------------------- |
|
||||
| result | Integer | The count matching entries |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
|
||||
:::
|
||||
|
||||
::: tab search
|
||||
|
||||
**`beforeSearch(params, populate)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| -------- | ------------- | ---------------------------- |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
| populate | Array{string} | Populate specific relations |
|
||||
|
||||
---
|
||||
|
||||
**`afterSearch(result, params)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| -------- | ------------- | ---------------------------- |
|
||||
| results | Array{Object} | The entries found |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
| populate | Array{string} | Populate specific relations |
|
||||
|
||||
:::
|
||||
|
||||
::: tab countSearch
|
||||
|
||||
**`beforeCountSearch(params)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | ---------------------------- |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
|
||||
---
|
||||
|
||||
**`afterCountSearch(result, params)`**
|
||||
|
||||
_Parameters:_
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------- | ---------------------------- |
|
||||
| result | Integer | The count matching entries |
|
||||
| params | Object | Find params _(e.g: filters)_ |
|
||||
|
||||
:::
|
||||
|
||||
@ -964,14 +1095,6 @@ Callbacks on:
|
||||
|
||||
### Example
|
||||
|
||||
:::: tabs
|
||||
|
||||
::: tab Mongoose
|
||||
|
||||
#### Mongoose
|
||||
|
||||
The entry is available through the `model` parameter.
|
||||
|
||||
**Path —** `./api/user/models/User.js`.
|
||||
|
||||
```js
|
||||
@ -979,43 +1102,68 @@ module.exports = {
|
||||
/**
|
||||
* Triggered before user creation.
|
||||
*/
|
||||
beforeCreate: async model => {
|
||||
// Hash password.
|
||||
const passwordHashed = await strapi.api.user.services.user.hashPassword(model.password);
|
||||
|
||||
// Set the password.
|
||||
model.password = passwordHashed;
|
||||
lifecycles: {
|
||||
async beforeCreate(data) {
|
||||
const passwordHashed = await strapi.api.user.services.user.hashPassword(data.password);
|
||||
data.password = passwordHashed;
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
::: tip
|
||||
You can mutate one of the parameters to change its properties. Make sure not to reassign the parameter as it will have no effect:
|
||||
|
||||
::: tab Bookshelf
|
||||
|
||||
#### Bookshelf
|
||||
|
||||
Each of these functions receives three parameters `model`, `attrs` and `options`. You have to return a Promise.
|
||||
|
||||
**Path —** `./api/user/models/User.js`.
|
||||
**This will Work**
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
/**
|
||||
* Triggered before user creation.
|
||||
*/
|
||||
beforeCreate: async (model, attrs, options) => {
|
||||
// Hash password.
|
||||
const passwordHashed = await strapi.api.user.services.user.hashPassword(
|
||||
model.attributes.password
|
||||
);
|
||||
lifecycles: {
|
||||
beforeCreate(data) {
|
||||
data.name = 'Some fixed name';
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
// Set the password.
|
||||
model.set('password', passwordHashed);
|
||||
**This will NOT Work**
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
lifecycles: {
|
||||
beforeCreate(data) {
|
||||
data = {
|
||||
...data,
|
||||
name: 'Some fixed name',
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
:::
|
||||
|
||||
:::::
|
||||
### Custom use
|
||||
|
||||
When you are building custom ORM specific queries the lifecycles will not be triggered. You can however call a lifecycle function directly if you wish.
|
||||
|
||||
**Bookshelf example**
|
||||
|
||||
**Path -** `./api/{apiName}/services/{serviceName}.js`
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
async createCustomEntry() {
|
||||
const ORMModel = strapi.query(modelName).model;
|
||||
|
||||
const newCustomEntry = await ORMModel.forge().save();
|
||||
|
||||
// trigger manually
|
||||
ORMModel.lifecycles.afterCreate(newCustomEntry.toJSON());
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
::: tip
|
||||
When calling a lifecycle function directly, you will need to make sur you call it with the expected parameters.
|
||||
:::
|
||||
|
||||
@ -4,41 +4,4 @@
|
||||
* Lifecycle callbacks for the `Address` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,41 +4,4 @@
|
||||
* Lifecycle callbacks for the `Category` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,41 +4,4 @@
|
||||
* Lifecycle callbacks for the `Country` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,41 +4,4 @@
|
||||
* Lifecycle callbacks for the `homepage` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,41 +4,4 @@
|
||||
* Lifecycle callbacks for the `Like` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,41 +4,4 @@
|
||||
* Lifecycle callbacks for the `Menu` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,41 +4,4 @@
|
||||
* Lifecycle callbacks for the `Menusection` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -5,40 +5,54 @@
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
lifecycles: {
|
||||
beforeCreate(...args) {
|
||||
// console.log('beforeCreate', ...args);
|
||||
},
|
||||
afterCreate(...args) {
|
||||
// console.log('afterCreate', ...args);
|
||||
},
|
||||
beforeUpdate(...args) {
|
||||
// console.log('beforeUpdate', ...args);
|
||||
},
|
||||
afterUpdate(...args) {
|
||||
// console.log('afterUpdate', ...args);
|
||||
},
|
||||
beforeDelete(...args) {
|
||||
// console.log('beforeDelete', ...args);
|
||||
},
|
||||
afterDelete(...args) {
|
||||
// console.log('afterDelete', ...args);
|
||||
},
|
||||
beforeFind(...args) {
|
||||
// console.log('beforeFind', ...args);
|
||||
},
|
||||
afterFind(...args) {
|
||||
// console.log('afterFind', ...args);
|
||||
},
|
||||
beforeFindOne(...args) {
|
||||
// console.log('beforeFindOne', ...args);
|
||||
},
|
||||
afterFindOne(...args) {
|
||||
// console.log('afterFindOne', ...args);
|
||||
},
|
||||
beforeCount(...args) {
|
||||
// console.log('beforeCount', ...args);
|
||||
},
|
||||
afterCount(...args) {
|
||||
// console.log('afterCount', ...args);
|
||||
},
|
||||
beforeSearch(...args) {
|
||||
// console.log('beforeSearch', ...args);
|
||||
},
|
||||
afterSearch(...args) {
|
||||
// console.log('afterSearch', ...args);
|
||||
},
|
||||
beforeCountSearch(...args) {
|
||||
// console.log('beforeCountSearch', ...args);
|
||||
},
|
||||
afterCountSearch(...args) {
|
||||
// console.log('afterCountSearch', ...args);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -4,41 +4,4 @@
|
||||
* Lifecycle callbacks for the `Review` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,40 +4,4 @@
|
||||
* Lifecycle callbacks for the `Admin` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model) => {},
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, result) => {},
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model) => {},
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, results) => {},
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model) => {},
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, result) => {},
|
||||
// Before creating a value.
|
||||
// Fired before `insert` query.
|
||||
// beforeCreate: async (model) => {},
|
||||
// After creating a value.
|
||||
// Fired after `insert` query.
|
||||
// afterCreate: async (model, result) => {},
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model) => {},
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, result) => {},
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model) => {},
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, result) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -16,21 +16,6 @@ const populateFetch = require('./populate');
|
||||
|
||||
const PIVOT_PREFIX = '_pivot_';
|
||||
|
||||
const LIFECYCLES = {
|
||||
creating: 'beforeCreate',
|
||||
created: 'afterCreate',
|
||||
destroying: 'beforeDestroy',
|
||||
destroyed: 'afterDestroy',
|
||||
updating: 'beforeUpdate',
|
||||
updated: 'afterUpdate',
|
||||
fetching: 'beforeFetch',
|
||||
'fetching:collection': 'beforeFetchAll',
|
||||
fetched: 'afterFetch',
|
||||
'fetched:collection': 'afterFetchAll',
|
||||
saving: 'beforeSave',
|
||||
saved: 'afterSave',
|
||||
};
|
||||
|
||||
const getDatabaseName = connection => {
|
||||
const dbName = _.get(connection.settings, 'database');
|
||||
const dbSchema = _.get(connection.settings, 'schema', 'public');
|
||||
@ -566,28 +551,12 @@ module.exports = ({ models, target }, ctx) => {
|
||||
// Load bookshelf plugin arguments from model options
|
||||
this.constructor.__super__.initialize.apply(this, arguments);
|
||||
|
||||
_.forEach(LIFECYCLES, (fn, key) => {
|
||||
if (_.isFunction(target[model.toLowerCase()][fn])) {
|
||||
this.on(key, target[model.toLowerCase()][fn]);
|
||||
}
|
||||
});
|
||||
|
||||
// Update withRelated level to bypass many-to-many association for polymorphic relationshiips.
|
||||
// Apply only during fetching.
|
||||
this.on('fetching fetching:collection', (instance, attrs, options) => {
|
||||
populateFetch(definition, options);
|
||||
|
||||
return _.isFunction(target[model.toLowerCase()]['beforeFetchAll'])
|
||||
? target[model.toLowerCase()]['beforeFetchAll']
|
||||
: Promise.resolve();
|
||||
});
|
||||
|
||||
this.on('saving', (instance, attrs) => {
|
||||
instance.attributes = _.assign(instance.attributes, mapper(attrs));
|
||||
|
||||
return _.isFunction(target[model.toLowerCase()]['beforeSave'])
|
||||
? target[model.toLowerCase()]['beforeSave']
|
||||
: Promise.resolve();
|
||||
});
|
||||
|
||||
const formatValue = createFormatter(definition.client);
|
||||
@ -598,37 +567,12 @@ module.exports = ({ models, target }, ctx) => {
|
||||
});
|
||||
}
|
||||
|
||||
function formatOutput(instance) {
|
||||
this.on('saved fetched fetched:collection', instance => {
|
||||
if (Array.isArray(instance.models)) {
|
||||
instance.models.forEach(entry => formatEntry(entry));
|
||||
} else {
|
||||
formatEntry(instance);
|
||||
}
|
||||
}
|
||||
|
||||
const events = [
|
||||
{
|
||||
name: 'saved',
|
||||
target: 'afterSave',
|
||||
},
|
||||
{
|
||||
name: 'fetched',
|
||||
target: 'afterFetch',
|
||||
},
|
||||
{
|
||||
name: 'fetched:collection',
|
||||
target: 'afterFetchAll',
|
||||
},
|
||||
];
|
||||
|
||||
events.forEach(event => {
|
||||
this.on(event.name, instance => {
|
||||
formatOutput(instance);
|
||||
|
||||
return _.isFunction(target[model.toLowerCase()][event.target])
|
||||
? target[model.toLowerCase()][event.target]
|
||||
: Promise.resolve();
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@ -82,19 +82,6 @@ module.exports = ({ models, target }, ctx) => {
|
||||
_.omitBy(definition.loadedModel, ({ type }) => type === 'virtual')
|
||||
);
|
||||
|
||||
// Initialize lifecycle callbacks.
|
||||
const preLifecycle = {
|
||||
validate: 'beforeCreate',
|
||||
find: 'beforeFetchAll',
|
||||
findOne: 'beforeFetch',
|
||||
findOneAndUpdate: 'beforeUpdate',
|
||||
findOneAndRemove: 'beforeDestroy',
|
||||
remove: 'beforeDestroy',
|
||||
update: 'beforeUpdate',
|
||||
updateOne: 'beforeUpdate',
|
||||
save: 'beforeSave',
|
||||
};
|
||||
|
||||
const findLifecycles = ['find', 'findOne', 'findOneAndUpdate', 'findOneAndRemove'];
|
||||
|
||||
/*
|
||||
@ -102,7 +89,6 @@ module.exports = ({ models, target }, ctx) => {
|
||||
It allows us to make Upload.find().populate('related')
|
||||
instead of Upload.find().populate('related.item')
|
||||
*/
|
||||
|
||||
const morphAssociations = definition.associations.filter(isPolymorphicAssoc);
|
||||
|
||||
const populateFn = createOnFetchPopulateFn({
|
||||
@ -115,45 +101,6 @@ module.exports = ({ models, target }, ctx) => {
|
||||
schema.pre(key, populateFn);
|
||||
});
|
||||
|
||||
Object.keys(preLifecycle).forEach(key => {
|
||||
const fn = preLifecycle[key];
|
||||
|
||||
if (_.isFunction(target[model.toLowerCase()][fn])) {
|
||||
schema.pre(key, function() {
|
||||
return target[model.toLowerCase()][fn](this);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const postLifecycle = {
|
||||
validate: 'afterCreate',
|
||||
findOneAndRemove: 'afterDestroy',
|
||||
remove: 'afterDestroy',
|
||||
update: 'afterUpdate',
|
||||
updateOne: 'afterUpdate',
|
||||
find: 'afterFetchAll',
|
||||
findOne: 'afterFetch',
|
||||
save: 'afterSave',
|
||||
};
|
||||
|
||||
// Mongoose doesn't allow post 'remove' event on model.
|
||||
// See https://github.com/Automattic/mongoose/issues/3054
|
||||
Object.keys(postLifecycle).forEach(key => {
|
||||
const fn = postLifecycle[key];
|
||||
|
||||
if (_.isFunction(target[model.toLowerCase()][fn])) {
|
||||
schema.post(key, function(doc, next) {
|
||||
target[model.toLowerCase()]
|
||||
[fn](this, doc)
|
||||
.then(next)
|
||||
.catch(err => {
|
||||
strapi.log.error(err);
|
||||
next(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Add virtual key to provide populate and reverse populate
|
||||
_.forEach(
|
||||
_.pickBy(definition.loadedModel, model => {
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const createQuery = require('../create-query');
|
||||
|
||||
describe('Database queries', () => {
|
||||
describe('Subsitute id with primaryKey in paramters', () => {
|
||||
test.each(['create', 'update', 'delete', 'find', 'findOne', 'search', 'count', 'countSearch'])(
|
||||
'Calling "%s" replaces id by the primaryKey in the params of the model before calling the underlying connector',
|
||||
async method => {
|
||||
const model = {
|
||||
primaryKey: 'testId',
|
||||
};
|
||||
const params = {
|
||||
id: 'someValue',
|
||||
};
|
||||
|
||||
const connectorQuery = {
|
||||
[method]: jest.fn(() => Promise.resolve({})),
|
||||
};
|
||||
|
||||
const query = createQuery({ model, connectorQuery });
|
||||
|
||||
await query[method](params);
|
||||
|
||||
expect(connectorQuery[method]).toHaveBeenCalledWith({
|
||||
testId: 'someValue',
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('Lifecycles', () => {
|
||||
test.each(['create', 'update', 'delete', 'find', 'findOne', 'search', 'count', 'countSearch'])(
|
||||
'Calling "%s" calls the before adn after lifecycle hooks with the correct arguments',
|
||||
async method => {
|
||||
const arg1 = {};
|
||||
const arg2 = {};
|
||||
const output = {};
|
||||
const beforeLifecycleMethod = jest.fn();
|
||||
const afterLifecycleMethod = jest.fn();
|
||||
const queryMethod = jest.fn(() => Promise.resolve(output));
|
||||
|
||||
const model = {
|
||||
lifecycles: {
|
||||
[`before${_.upperFirst(method)}`]: beforeLifecycleMethod,
|
||||
[`after${_.upperFirst(method)}`]: afterLifecycleMethod,
|
||||
},
|
||||
};
|
||||
|
||||
const connectorQuery = {
|
||||
[method]: queryMethod,
|
||||
};
|
||||
|
||||
const query = createQuery({ model, connectorQuery });
|
||||
|
||||
await query[method](arg1, arg2);
|
||||
|
||||
expect(queryMethod).toHaveBeenCalledWith(arg1, arg2);
|
||||
expect(beforeLifecycleMethod).toHaveBeenCalledWith(arg1, arg2);
|
||||
expect(afterLifecycleMethod).toHaveBeenCalledWith(output, arg1, arg2);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
@ -1,85 +1,80 @@
|
||||
'use strict';
|
||||
|
||||
const { replaceIdByPrimaryKey } = require('../utils/primary-key');
|
||||
const { executeBeforeLifecycle, executeAfterLifecycle } = require('../utils/lifecycles');
|
||||
|
||||
/**
|
||||
* @param {Object} opts options
|
||||
* @param {Object} opts.model The ORM model
|
||||
* @param {Object} opts.connectorQuery The ORM queries implementation
|
||||
*/
|
||||
module.exports = function createQuery(opts) {
|
||||
return new Query(opts);
|
||||
const { model, connectorQuery } = opts;
|
||||
|
||||
return {
|
||||
get model() {
|
||||
return model;
|
||||
},
|
||||
|
||||
get orm() {
|
||||
return model.orm;
|
||||
},
|
||||
|
||||
get primaryKey() {
|
||||
return model.primaryKey;
|
||||
},
|
||||
|
||||
get associations() {
|
||||
return model.associations;
|
||||
},
|
||||
|
||||
/**
|
||||
* Run custom database logic
|
||||
*/
|
||||
custom(mapping) {
|
||||
if (typeof mapping === 'function') {
|
||||
return mapping.bind(this, { model: this.model });
|
||||
}
|
||||
|
||||
if (!mapping[this.orm]) {
|
||||
throw new Error(`Missing mapping for orm ${this.orm}`);
|
||||
}
|
||||
|
||||
if (typeof mapping[this.orm] !== 'function') {
|
||||
throw new Error(`Custom queries must be functions received ${typeof mapping[this.orm]}`);
|
||||
}
|
||||
|
||||
return mapping[this.model.orm].call(this, { model: this.model });
|
||||
},
|
||||
|
||||
create: createQueryWithLifecycles({ query: 'create', model, connectorQuery }),
|
||||
update: createQueryWithLifecycles({ query: 'update', model, connectorQuery }),
|
||||
delete: createQueryWithLifecycles({ query: 'delete', model, connectorQuery }),
|
||||
find: createQueryWithLifecycles({ query: 'find', model, connectorQuery }),
|
||||
findOne: createQueryWithLifecycles({ query: 'findOne', model, connectorQuery }),
|
||||
count: createQueryWithLifecycles({ query: 'count', model, connectorQuery }),
|
||||
search: createQueryWithLifecycles({ query: 'search', model, connectorQuery }),
|
||||
countSearch: createQueryWithLifecycles({ query: 'countSearch', model, connectorQuery }),
|
||||
};
|
||||
};
|
||||
|
||||
class Query {
|
||||
constructor({ model, connectorQuery }) {
|
||||
this.connectorQuery = connectorQuery;
|
||||
this.model = model;
|
||||
}
|
||||
// wraps a connectorQuery call with:
|
||||
// - param substitution
|
||||
// - lifecycle hooks
|
||||
const createQueryWithLifecycles = ({ query, model, connectorQuery }) => async (params, ...rest) => {
|
||||
// substitute id for primaryKey value in params
|
||||
const newParams = replaceIdByPrimaryKey(params, model);
|
||||
const queryArguments = [newParams, ...rest];
|
||||
|
||||
get orm() {
|
||||
return this.model.orm;
|
||||
}
|
||||
// execute before hook
|
||||
await executeBeforeLifecycle(query, model, ...queryArguments);
|
||||
|
||||
get primaryKey() {
|
||||
return this.model.primaryKey;
|
||||
}
|
||||
// execute query
|
||||
const result = await connectorQuery[query](...queryArguments);
|
||||
|
||||
get associations() {
|
||||
return this.model.associations;
|
||||
}
|
||||
// execute after hook with result and arguments
|
||||
await executeAfterLifecycle(query, model, result, ...queryArguments);
|
||||
|
||||
/**
|
||||
* Run custom database logic
|
||||
*/
|
||||
custom(mapping) {
|
||||
if (typeof mapping === 'function') {
|
||||
return mapping.bind(this, { model: this.model });
|
||||
}
|
||||
|
||||
if (!mapping[this.orm]) {
|
||||
throw new Error(`Missing mapping for orm ${this.orm}`);
|
||||
}
|
||||
|
||||
if (typeof mapping[this.orm] !== 'function') {
|
||||
throw new Error(`Custom queries must be functions received ${typeof mapping[this.orm]}`);
|
||||
}
|
||||
|
||||
return mapping[this.model.orm].call(this, { model: this.model });
|
||||
}
|
||||
|
||||
find(params = {}, ...args) {
|
||||
const newParams = replaceIdByPrimaryKey(params, this.model);
|
||||
return this.connectorQuery.find(newParams, ...args);
|
||||
}
|
||||
|
||||
findOne(params = {}, ...args) {
|
||||
const newParams = replaceIdByPrimaryKey(params, this.model);
|
||||
return this.connectorQuery.findOne(newParams, ...args);
|
||||
}
|
||||
|
||||
create(params = {}, ...args) {
|
||||
const newParams = replaceIdByPrimaryKey(params, this.model);
|
||||
return this.connectorQuery.create(newParams, ...args);
|
||||
}
|
||||
|
||||
update(params = {}, ...args) {
|
||||
const newParams = replaceIdByPrimaryKey(params, this.model);
|
||||
return this.connectorQuery.update(newParams, ...args);
|
||||
}
|
||||
|
||||
delete(params = {}, ...args) {
|
||||
const newParams = replaceIdByPrimaryKey(params, this.model);
|
||||
return this.connectorQuery.delete(newParams, ...args);
|
||||
}
|
||||
|
||||
count(params = {}, ...args) {
|
||||
const newParams = replaceIdByPrimaryKey(params, this.model);
|
||||
return this.connectorQuery.count(newParams, ...args);
|
||||
}
|
||||
|
||||
search(params = {}, ...args) {
|
||||
const newParams = replaceIdByPrimaryKey(params, this.model);
|
||||
return this.connectorQuery.search(newParams, ...args);
|
||||
}
|
||||
|
||||
countSearch(params = {}, ...args) {
|
||||
const newParams = replaceIdByPrimaryKey(params, this.model);
|
||||
return this.connectorQuery.countSearch(newParams, ...args);
|
||||
}
|
||||
}
|
||||
// return result
|
||||
return result;
|
||||
};
|
||||
|
||||
20
packages/strapi-database/lib/utils/lifecycles.js
Normal file
20
packages/strapi-database/lib/utils/lifecycles.js
Normal file
@ -0,0 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
|
||||
const executeLifecycle = async (lifecycle, model, ...args) => {
|
||||
if (_.has(model, `lifecycles.${lifecycle}`)) {
|
||||
await model.lifecycles[lifecycle](...args);
|
||||
}
|
||||
};
|
||||
|
||||
const executeBeforeLifecycle = (lifecycle, model, ...args) =>
|
||||
executeLifecycle(`before${_.upperFirst(lifecycle)}`, model, ...args);
|
||||
|
||||
const executeAfterLifecycle = (lifecycle, model, ...args) =>
|
||||
executeLifecycle(`after${_.upperFirst(lifecycle)}`, model, ...args);
|
||||
|
||||
module.exports = {
|
||||
executeBeforeLifecycle,
|
||||
executeAfterLifecycle,
|
||||
};
|
||||
@ -1,55 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Lifecycle callbacks for the `<%= name %>` model.
|
||||
* Read the documentation (https://strapi.io/documentation/3.0.0-beta.x/concepts/models.html#life-cycle-callbacks)
|
||||
* to customize this model
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model, columns, options) => {},
|
||||
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, response, options) => {},
|
||||
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -1,55 +1,8 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Lifecycle callbacks for the `<%= name %>` model.
|
||||
* Read the documentation (https://strapi.io/documentation/3.0.0-beta.x/concepts/models.html#life-cycle-callbacks)
|
||||
* to customize this model
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model, attrs, options) => {},
|
||||
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, response, options) => {},
|
||||
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchCollection: async (model, columns, options) => {},
|
||||
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchCollection: async (model, columns, options) => {},
|
||||
|
||||
// Before fetching a value.
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model, columns, options) => {},
|
||||
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, response, options) => {},
|
||||
|
||||
// Before creating a value.
|
||||
// Fired before an `insert` query.
|
||||
// beforeCreate: async (model, attrs, options) => {},
|
||||
|
||||
// After creating a value.
|
||||
// Fired after an `insert` query.
|
||||
// afterCreate: async (model, attrs, options) => {},
|
||||
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model, attrs, options) => {},
|
||||
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, attrs, options) => {},
|
||||
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model, attrs, options) => {},
|
||||
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, attrs, options) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
/**
|
||||
* Upload plugin bootstrapi.
|
||||
* Upload plugin bootstrap.
|
||||
*
|
||||
* It initializes the provider and sets the default settings in db.
|
||||
*/
|
||||
@ -26,6 +26,8 @@ module.exports = async () => {
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
await pruneObsoleteRelations();
|
||||
};
|
||||
|
||||
const createProvider = ({ provider, providerOptions }) => {
|
||||
@ -52,3 +54,28 @@ const baseProvider = {
|
||||
throw new Error('Provider delete method is not implemented');
|
||||
},
|
||||
};
|
||||
|
||||
const pruneObsoleteRelations = async () => {
|
||||
const { upload: plugin } = strapi.plugins;
|
||||
const modelIsNotDefined = !plugin || !plugin.models || !plugin.models.file;
|
||||
|
||||
if (modelIsNotDefined) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
await strapi.query('file', 'upload').custom(pruneObsoleteRelationsQuery)();
|
||||
};
|
||||
|
||||
const pruneObsoleteRelationsQuery = ({ model }) => {
|
||||
if (model.orm !== 'mongoose') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
const models = Array.from(strapi.db.models.values());
|
||||
const modelsId = models.map(model => model.globalId);
|
||||
|
||||
return model.updateMany(
|
||||
{ related: { $elemMatch: { kind: { $nin: modelsId } } } },
|
||||
{ $pull: { related: { kind: { $nin: modelsId } } } }
|
||||
);
|
||||
};
|
||||
|
||||
@ -4,51 +4,4 @@
|
||||
* Lifecycle callbacks for the `File` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model) => {},
|
||||
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, result) => {},
|
||||
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model) => {},
|
||||
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, results) => {},
|
||||
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model) => {},
|
||||
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, result) => {},
|
||||
|
||||
// Before creating a value.
|
||||
// Fired before `insert` query.
|
||||
// beforeCreate: async (model) => {},
|
||||
|
||||
// After creating a value.
|
||||
// Fired after `insert` query.
|
||||
// afterCreate: async (model, result) => {},
|
||||
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model) => {},
|
||||
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, result) => {},
|
||||
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model) => {},
|
||||
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, result) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,51 +4,4 @@
|
||||
* Lifecycle callbacks for the `Permission` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model) => {},
|
||||
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, result) => {},
|
||||
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model) => {},
|
||||
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, results) => {},
|
||||
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model) => {},
|
||||
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, result) => {},
|
||||
|
||||
// Before creating a value.
|
||||
// Fired before `insert` query.
|
||||
// beforeCreate: async (model) => {},
|
||||
|
||||
// After creating a value.
|
||||
// Fired after `insert` query.
|
||||
// afterCreate: async (model, result) => {},
|
||||
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model) => {},
|
||||
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, result) => {},
|
||||
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model) => {},
|
||||
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, result) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,51 +4,4 @@
|
||||
* Lifecycle callbacks for the `Role` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model) => {},
|
||||
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, result) => {},
|
||||
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model) => {},
|
||||
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, results) => {},
|
||||
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model) => {},
|
||||
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, result) => {},
|
||||
|
||||
// Before creating a value.
|
||||
// Fired before `insert` query.
|
||||
// beforeCreate: async (model) => {},
|
||||
|
||||
// After creating a value.
|
||||
// Fired after `insert` query.
|
||||
// afterCreate: async (model, result) => {},
|
||||
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model) => {},
|
||||
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, result) => {},
|
||||
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model) => {},
|
||||
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, result) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
@ -4,51 +4,4 @@
|
||||
* Lifecycle callbacks for the `User` model.
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
// Before saving a value.
|
||||
// Fired before an `insert` or `update` query.
|
||||
// beforeSave: async (model) => {},
|
||||
|
||||
// After saving a value.
|
||||
// Fired after an `insert` or `update` query.
|
||||
// afterSave: async (model, result) => {},
|
||||
|
||||
// Before fetching all values.
|
||||
// Fired before a `fetchAll` operation.
|
||||
// beforeFetchAll: async (model) => {},
|
||||
|
||||
// After fetching all values.
|
||||
// Fired after a `fetchAll` operation.
|
||||
// afterFetchAll: async (model, results) => {},
|
||||
|
||||
// Fired before a `fetch` operation.
|
||||
// beforeFetch: async (model) => {},
|
||||
|
||||
// After fetching a value.
|
||||
// Fired after a `fetch` operation.
|
||||
// afterFetch: async (model, result) => {},
|
||||
|
||||
// Before creating a value.
|
||||
// Fired before `insert` query.
|
||||
// beforeCreate: async (model) => {},
|
||||
|
||||
// After creating a value.
|
||||
// Fired after `insert` query.
|
||||
// afterCreate: async (model, result) => {},
|
||||
|
||||
// Before updating a value.
|
||||
// Fired before an `update` query.
|
||||
// beforeUpdate: async (model) => {},
|
||||
|
||||
// After updating a value.
|
||||
// Fired after an `update` query.
|
||||
// afterUpdate: async (model, result) => {},
|
||||
|
||||
// Before destroying a value.
|
||||
// Fired before a `delete` query.
|
||||
// beforeDestroy: async (model) => {},
|
||||
|
||||
// After destroying a value.
|
||||
// Fired after a `delete` query.
|
||||
// afterDestroy: async (model, result) => {}
|
||||
};
|
||||
module.exports = {};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user