@knorm/knorm
Advanced tools
Comparing version 1.0.1 to 1.1.0
@@ -0,1 +1,11 @@ | ||
<a name="1.1.0"></a> | ||
# [1.1.0](https://github.com/knorm/knorm/compare/v1.0.1...v1.1.0) (2018-07-26) | ||
### Features | ||
* **Query:** add the failing sql to query errors ([ad8c9da](https://github.com/knorm/knorm/commit/ad8c9da)) | ||
<a name="1.0.1"></a> | ||
@@ -2,0 +12,0 @@ ## [1.0.1](https://github.com/knorm/knorm/compare/v1.0.0...v1.0.1) (2018-07-05) |
@@ -18,5 +18,2 @@ # Knorm | ||
* [Transaction](api/transaction.md#transaction) | ||
* [KnormError](api/knorm-error.md#knorm-error) | ||
* [QueryError](api/query-error.md#query-error) | ||
* [ValidationError](api/validation-error.md#validation-error) | ||
@@ -27,4 +24,15 @@ ## Options | ||
| Option | Type | Description | | ||
| --------------- | -------- | ------------------------------------------------------------------------------------------------------------- | | ||
| `fieldToColumn` | function | a function used to map field names to column names e.g. [snakeCase](https://lodash.com/docs/4.17.4#snakeCase) | | ||
| Option | Type | Default | Description | | ||
| --------------- | -------- | ------- | ------------------------------------------------------------------------------------------------------------- | | ||
| `debug` | boolean | `false` | if `true`, enables [debug mode](#debug-mode) | | ||
| `fieldToColumn` | function | none | a function used to map field names to column names e.g. [snakeCase](https://lodash.com/docs/4.17.4#snakeCase) | | ||
## Debug mode | ||
Debug mode turns on features that help with debugging but at a cost to | ||
performance. Features enabled: | ||
* more accurate stack traces for database (fetch, insert, update and delete) | ||
errors. this is meant to workaround [this async/await issue](https://github.com/nodejs/node/issues/11865) | ||
!> Debug mode should not be used in production! |
@@ -40,2 +40,6 @@ # Model | ||
## Model.prototype.knorm | ||
## Model.prototype.models | ||
## Model.prototype.getFieldData([options]) : Object | ||
@@ -67,2 +71,6 @@ | ||
## Model.knorm | ||
## Model.models | ||
## Model.count([options]) : Promise => Number | ||
@@ -69,0 +77,0 @@ |
@@ -39,7 +39,13 @@ ## Query.knex | ||
## Query.prototype.query(sql) : Promise => [] | ||
## Query.prototype.sql | ||
## Query.prototype.setOptions(options) : Query | ||
## Query.prototype.debug([debug]) : Query | ||
## Query.prototype.field(field) : Query | ||
## Query.prototype.distinct(field) : Query | ||
## Query.prototype.distinct(fields) : Query | ||
@@ -64,34 +70,6 @@ ## Query.prototype.fields(fields) : Query | ||
## Query.prototype.transaction(transaction, [options]) : Query | ||
## Query.prototype.where(where) : Query | ||
> alias: Query.prototype.within(transaction, [options]) | ||
## Query.prototype.where(fields) : Query | ||
## Query.prototype.whereNot(fields) : Query | ||
## Query.prototype.orWhere(fields) : Query | ||
## Query.prototype.orWhereNot(fields) : Query | ||
## Query.prototype.having(fields) : Query | ||
Knex QueryBuilder's [having](http://knexjs.org/#Builder-having) method requires | ||
an operator, therefore calls to `Query.prototype.having` must have an operator: | ||
```js | ||
new Query(User).having({ | ||
id: { | ||
operator: '=', | ||
value: 1 | ||
} | ||
}); | ||
``` | ||
## Query.prototype.havingNot(fields) : Query | ||
## Query.prototype.orHaving(fields) : Query | ||
## Query.prototype.orHavingNot(fields) : Query | ||
## Query.prototype.limit(limit) : Query | ||
@@ -98,0 +76,0 @@ |
@@ -1,9 +0,9 @@ | ||
## Transaction.knex | ||
## Transaction([callback]) | ||
## Transaction(callback) | ||
## Transaction.prototype.execute() : Promise | ||
## Transaction.prototype.then() : Promise | ||
## Transaction.prototype.begin() : Promise | ||
## Transaction.prototype.catch() : Promise | ||
## Transaction.prototype.commit() : Promise | ||
## Transaction.prototype.rollback() : Promise |
@@ -15,8 +15,4 @@ # Getting started | ||
const knorm = require('@knorm/knorm'); | ||
const orm = knorm(/* options */); | ||
const { Model } = knorm(/* options */); | ||
// orm contains `Model`, `Field`, `Query`, `Transaction` etc classes | ||
const { Model } = orm; | ||
// let's create a User model | ||
class User extends Model {} | ||
@@ -27,2 +23,6 @@ ``` | ||
> the `knorm` factory returns an ORM instance with [Model](api/model.md#model), | ||
[Field](api/field.md#field), [Query](api/query.md#query) and | ||
[Transaction](api/transaction.md#transaction) | ||
## Enabling database access | ||
@@ -63,12 +63,12 @@ | ||
User.fields = { id: 'integer', names: 'string' }; | ||
``` | ||
const doStuff = async () => { | ||
const user = await new User({ id: 1, names: 'Foo Bar' }).insert(); | ||
console.log(user); // => { id: 1, names: 'Foo Bar' } | ||
With this setup you can now manipulate data: | ||
const users = await User.fetch(); | ||
console.log(users); // => [ { id: 1, names: 'Foo Bar' } ] | ||
} | ||
```js | ||
const user = await new User({ id: 1, names: 'Foo Bar' }).insert(); | ||
console.log(user); // => User({ id: 1, names: 'Foo Bar' }) | ||
doStuff(); | ||
const users = await User.fetch(); | ||
console.log(users); // => [ User({ id: 1, names: 'Foo Bar' }) ] | ||
``` | ||
@@ -75,0 +75,0 @@ |
# Models | ||
Models are synonymous to database tables. They provide the core functionality | ||
for setting, validating, saving, updating and deleting data. All models should | ||
inherit the base [Model](api/model.md#model) class. | ||
for setting, validating, saving, updating and deleting data. All models inherit | ||
the base [Model](api/model.md#model) class. | ||
## Model config | ||
Models are configured via static properties: | ||
Models are configured through these static properties: | ||
| Property | Type | Default | Description | | ||
| ---------------- | --------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `Model.table` | string (**required**) | none | Configures the model's table-name. **NOTE:** even though this is required, you can still have models that don't have a `table` property if they don't perform any database operations | | ||
| `Model.fields` | object | none | Configures the model's fields. See the [fields guide](guides/fields.md#fields) for more info | | ||
| `Model.virtuals` | object | none | Configures the model's virtual fields. See the [virtuals guide](guides/virtuals.md#virtuals) for more info | | ||
| `Model.Query` | [Query](api/query.md#query) | [Query](api/query.md#query) | The `Query` class that the model uses to perform database operations. This allows [customizing queries](#customizing-queries) per model. | | ||
| `Model.Field` | [Field](api/field.md#field) | [Field](api/field.md#field) | The `Field` class that the model uses to create field instances. Also allows customizing fields per model. | | ||
| Property | Type | Default | Description | | ||
| ---------------- | --------------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `Model.table` | string (**required**) | none | Configures the model's table-name. **NOTE:** this config can be omitted if the model is not used for performing any database operations (i.e. fetching, saving, deleting etc) | | ||
| `Model.fields` | object | none | Configures the model's fields. See the [fields guide](guides/fields.md#fields) for more info | | ||
| `Model.virtuals` | object | none | Configures the model's virtual fields. See the [virtuals guide](guides/virtuals.md#virtuals) for more info | | ||
| `Model.Query` | [Query](api/query.md#query) | [Query](api/query.md#query) | The `Query` class that the model uses to perform database operations. This allows [customizing queries](#customizing-queries) per model. | | ||
| `Model.Field` | [Field](api/field.md#field) | [Field](api/field.md#field) | The `Field` class that the model uses to create field instances. Also allows customizing fields per model. | | ||
@@ -29,3 +29,2 @@ > See the [Model](api/model.md#model) docs for Model API documentation | ||
User.fields = { firstName: { type: 'string' }, lastName: { type: 'string' } }; | ||
User.virtuals = { | ||
@@ -101,3 +100,3 @@ names: { | ||
## Manipulating database data | ||
## Saving, fetching and deleting data | ||
@@ -124,7 +123,9 @@ For all [Model](api/model.md#model) instances, you can save, retrieve or delete | ||
> `options` are optional in all methods | ||
> See the [Query](api/query.md#query) docs for supported options | ||
All the methods update the instance with the latest data from the database, so | ||
after an update you do not need to re-fetch for example (this can be disabled | ||
with the `returning` option though). | ||
after an update you do not need to re-fetch the row (this can be disabled with | ||
the `returning` option though). | ||
@@ -139,3 +140,3 @@ The [update](api/model.md#modelprototypeupdateoptions-promise-gt-model), | ||
All the methods also have static variants that instead enable manipulating | ||
All the methods also have static variants that instead enable working with | ||
multiple records: | ||
@@ -160,9 +161,13 @@ | ||
!> A significant difference between the instance and static methods is that the | ||
instance methods will throw an error if the record is not found in the database | ||
(for fetch, delete and update operations). | ||
> `options` are optional in all methods | ||
In addition, you can configure various "ByField" methods for primary and unique | ||
fields with the `methods` [field config option](guides/fields.md#field-config): | ||
!> Static methods work on multiple rows while the instance methods only work on | ||
a single row! | ||
!> Instance methods will throw automatically an error if the record is not found | ||
in the database (for fetch, delete and update operations). | ||
In addition, you can configure various "ByField" methods with the `methods` | ||
[field config option](guides/fields.md#field-config): | ||
```js | ||
@@ -195,3 +200,3 @@ User.fields = { email: { type: 'email', unique: true, methods: true } }; | ||
super(...args); | ||
this.whereNot({ type: 'system' }); | ||
this.where({ type: 'system' }); | ||
} | ||
@@ -198,0 +203,0 @@ }; |
@@ -6,6 +6,8 @@ * Guides | ||
* [Virtuals](guides/virtuals.md#virtuals) | ||
* [Queries](guides/queries.md#queries) | ||
* [Transactions](guides/transactions.md#transactions) | ||
* [Validation](guides/validation.md#validation) | ||
* [Relations](guides/relations.md#relations) | ||
* [Plugins](guides/plugins.md#plugins) | ||
* API | ||
* Api Docs | ||
* [Knorm](api/knorm.md#knorm) | ||
@@ -19,4 +21,10 @@ * [Model](api/model.md#model) | ||
* [ValidationError](api/validation-error.md#validation-error) | ||
* Plugins | ||
* [@knorm/postgres](knorm-postgres.md) | ||
* [@knorm/relations](knorm-relations.md) | ||
* [@knorm/soft-delete](knorm-soft-delete.md) | ||
* [@knorm/paginate](knorm-paginate.md) | ||
* [@knorm/timestamps](knorm-timestamps.md) | ||
* [README](readme.md) | ||
* [LICENSE](license.md) | ||
* [CHANGELOG](changelog.md) |
@@ -520,4 +520,4 @@ const { upperFirst } = require('lodash'); | ||
Model.prototype.knorm = Model.knorm = null; | ||
Model.prototype.models = Model.models = {}; | ||
Model.knorm = Model.prototype.knorm = null; | ||
Model.models = Model.prototype.models = {}; | ||
@@ -524,0 +524,0 @@ module.exports = Model; |
@@ -575,3 +575,6 @@ const { difference } = require('lodash'); | ||
_updateStack(error, stack) { | ||
formatError(error, { stack, sql }) { | ||
if (sql) { | ||
error.sql = this.options.debug ? sql.toString() : sql.toParams().text; | ||
} | ||
if (!stack) { | ||
@@ -592,12 +595,8 @@ return error; | ||
const sql = await this.prepareFetch(options); | ||
let rows; | ||
try { | ||
rows = await this.query(sql); | ||
} catch (error) { | ||
throw this._updateStack( | ||
const rows = await this.query(sql).catch(error => { | ||
throw this.formatError( | ||
new this.constructor.FetchError({ error, query: this }), | ||
stack | ||
{ stack, sql } | ||
); | ||
} | ||
}); | ||
@@ -609,4 +608,4 @@ if (!rows.length) { | ||
rows = this.parseRows(rows); | ||
return this.options.first ? rows[0] : rows; | ||
const parsedRows = this.parseRows(rows); | ||
return this.options.first ? parsedRows[0] : parsedRows; | ||
} | ||
@@ -618,12 +617,8 @@ | ||
const sql = await this.prepareDelete(options); | ||
let rows; | ||
try { | ||
rows = await this.query(sql); | ||
} catch (error) { | ||
throw this._updateStack( | ||
const rows = await this.query(sql).catch(error => { | ||
throw this.formatError( | ||
new this.constructor.DeleteError({ error, query: this }), | ||
stack | ||
{ stack, sql } | ||
); | ||
} | ||
}); | ||
@@ -637,4 +632,4 @@ if (!rows.length) { | ||
rows = this.parseRows(rows); | ||
return this.options.first ? rows[0] : rows; | ||
const parsedRows = this.parseRows(rows); | ||
return this.options.first ? parsedRows[0] : parsedRows; | ||
} | ||
@@ -651,15 +646,13 @@ | ||
try { | ||
await Promise.all( | ||
sqls.map(async sql => { | ||
const batch = await this.query(sql); | ||
rows = rows.concat(batch); | ||
}) | ||
); | ||
} catch (error) { | ||
throw this._updateStack( | ||
new this.constructor.InsertError({ error, query: this }), | ||
stack | ||
); | ||
} | ||
await Promise.all( | ||
sqls.map(async sql => { | ||
const batch = await this.query(sql).catch(error => { | ||
throw this.formatError( | ||
new this.constructor.InsertError({ error, query: this }), | ||
{ stack, sql } | ||
); | ||
}); | ||
rows = rows.concat(batch); | ||
}) | ||
); | ||
} | ||
@@ -674,4 +667,4 @@ | ||
rows = this.parseRows(rows); | ||
return this.options.first ? rows[0] : rows; | ||
const parsedRows = this.parseRows(rows); | ||
return this.options.first ? parsedRows[0] : parsedRows; | ||
} | ||
@@ -695,15 +688,13 @@ | ||
try { | ||
await Promise.all( | ||
sqls.map(async sql => { | ||
const batch = await this.query(sql); | ||
rows = rows.concat(batch); | ||
}) | ||
); | ||
} catch (error) { | ||
throw this._updateStack( | ||
new this.constructor.UpdateError({ error, query: this }), | ||
stack | ||
); | ||
} | ||
await Promise.all( | ||
sqls.map(async sql => { | ||
const batch = await this.query(sql).catch(error => { | ||
throw this.formatError( | ||
new this.constructor.UpdateError({ error, query: this }), | ||
{ stack, sql } | ||
); | ||
}); | ||
rows = rows.concat(batch); | ||
}) | ||
); | ||
} | ||
@@ -718,4 +709,4 @@ | ||
rows = this.parseRows(rows); | ||
return this.options.first ? rows[0] : rows; | ||
const parsedRows = this.parseRows(rows); | ||
return this.options.first ? parsedRows[0] : parsedRows; | ||
} | ||
@@ -753,4 +744,4 @@ | ||
Query.prototype.knorm = Query.knorm = null; | ||
Query.prototype.models = Query.models = {}; | ||
Query.knorm = Query.prototype.knorm = null; | ||
Query.models = Query.prototype.models = {}; | ||
@@ -757,0 +748,0 @@ module.exports = Query; |
@@ -65,5 +65,5 @@ const KnormError = require('./KnormError'); | ||
Transaction.prototype.knorm = Transaction.knorm = null; | ||
Transaction.prototype.models = Transaction.models = {}; | ||
Transaction.knorm = Transaction.prototype.knorm = null; | ||
Transaction.models = Transaction.prototype.models = {}; | ||
module.exports = Transaction; |
{ | ||
"name": "@knorm/knorm", | ||
"version": "1.0.1", | ||
"version": "1.1.0", | ||
"description": "A purely ES6 class-based ORM for Node.js", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
405359
56
9396