README
TL;DR manual
.create(data, options)
- creates new record with given data
- for optimized batch create use
bulkCreate(data[], options)
.detail(filters, options)
- gets a single record based on filters
.list(filters, options)
- get a list of records based on filters
.update(filters, data, options)
- updates a record based on filters with given data
.delete(filters, options)
- deletes records based on filters (if empty, deletes all)
🧙 Databless uses Bookshelf for underlying models, and even though Databless should be enough for most of the times, refer Bookshelf documentation for options if necessary, as they are passed to save/fetch/fetchAll/destroy metods as options.
Model
creating a model
const userModel = createModel({ adapter: () => knex // Knex getter collectionName: 'users' // Table name attributes: { // Record properties id: { type: 'number' }, name: { type: 'string' } } })
attributes
- define model shape and propety types
- not defined attributes are filtered before inserting/updating into a database
custom serialization
- via
attribute.serialize
objectStoredAsJson: { type: 'string', // serialize before inserting into a database serialize: x => JSON.stringify(x || null), // deserialize from database shape // deserialize can also be used to define attribute TS type, e.g. (x: string): MyEnum => x deserialize: x => JSON.parse(x), }
- via
bulk create
- via
bulkCreate(data[], options)
- uses knex Batch insert
- via
Repository
- via
createRepository(model)
- helper to create CRUD methods bound to a model
Filtering
via
filters
(except custom queries)exact match
{ foo: 'bar' } // SELECT ... WHERE foo='bar'
where-in
{ foo: ['bar', 'baz'] } // SELECT ... WHERE foo IN ('bar', 'baz')
inequality
- prefix value with one of
>
,<
,>=
,<=
{ foo: '>2' } // SELECT ... WHERE foo > 2
- prefix value with one of
searching
- only left and right wildcards are supported
{ foo: '*abc*' } // SELECT ... WHERE foo LIKE '%abc%' { foo: 'abc*' } // SELECT ... WHERE foo LIKE 'abc%' { foo: '*abc' } // SELECT ... WHERE foo LIKE '%abc'
custom queries
- via
options.qb
parametr options.qb
handler is passed to Bookshelfmodel.query(arguments)
, see docs- ⚠️ Use with care - any SQL you make is processed, means you can group, join, add columns and change the logic output of completely and the return value and types dont have to match.
{ qb: (qb: Knex.QueryBuilder) => qb.whereRaw('...') } // SELECT WHERE ...
- via
custom model filters
- via
Model.filters
andfilters
- allows you to use additional filters in
filters
(apart from Model.attributes) - define in
Model.filters
first, use infilters
second - ⚠️ Don't use this to overwrite any of the default Model.attribute filters, only add new filters
// Simplified example for brevity Model({ attributes: { /* */ }, filters: { myAwesomeFilter: (value, options) => {/* */} } }) detail({ myAwesomeFilter: awesomeValue })
- via
Counting
- via
options.count
- use
count: true
to get number of filtered records - filtering applies
Ordering
via
options.order
default ordering
{ order: 'foo' } // SELECT ... ORDER BY foo ASC
asc ordering
{ order: '+foo' } // SELECT ... ORDER BY foo ASC
desc ordering
{ order: '-foo' } // SELECT ... ORDER BY foo DESC
order by multiple
{ order: ['+foo', '-baz'] } // SELECT ... ORDER BY foo ASC, baz DESC
Pagination
via
options.limit
andoptions.offset
if either of
limit
oroffset
is defined, the other is filled with defaults (defaults: limit=10, offset=0){ limit: 10, offset: 0 } // SELECT ... LIMIT 10 OFFSET 0
Relations
Define a relation
via attribute of type=
relation
books: { type: 'relation', targetModel: () => bookModel, // Databless model getter relation: bookshelfRelation.createHasMany(/* ... */), // Resolves to Bookshelf relation // books() { // return this.hasMany('Book') // } }
refer to Bookshelf docs if you want to take full advantage of configuration createBelongsTo/createHasMany/createBelongsToMany/createHasOne
Populating relation properties
via
options.withRelated
on.list
,.detail
// Simplified example for brevity // Author { id, name } // Book { id, author: { relation: { targetModel: Author /*... */} } } const book = Books.detail({ id }, { withRelated: ['author' ] }) // { id, author: Author }
invokes original
withRelated
on underlying Boookshelf model
Reflexive relation
- via
targetModel='self'
TODO
- Range queries
- Like queries
- Option typing
- Custom relation queries (e.g. in Bookshelf
this.hasMany().where(...)
) - Custom queries (via options.qb)
- Pagination (limit/offset)
- Cursor streaming
- Model serialization/deserialization
- (docs) knex-stringgify doesnt work on sqlite in memory
withRelated
should be optionalwithRelated
shouldn't be available for update/create
Discussion
- Fetch all (fetchAll option)
- Default pagination
- Bug: Knex connection reuse (if a adapter getter fn value changes, its never used)
Test
You can create database via docker-compose
sudo docker-compose -f docker-compose/docker-compose.yml up
and run the tests
npm t
License
This project is licensed under MIT.