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
- [x] Range queries
- [x] Like queries
- [x] Option typing
- [x] Custom relation queries (e.g. in Bookshelf
this.hasMany().where(...)
) - [x] Custom queries (via options.qb)
- [x] Pagination (limit/offset)
- [ ] Cursor streaming
- [x] Model serialization/deserialization
- [ ] (docs) knex-stringgify doesnt work on sqlite in memory
- [ ]
withRelated
should be optional - [ ]
withRelated
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.