npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ruanmartinelli/knex-model

v0.3.0

Published

> A wrapper around the Knex library using ES6 classes.

Readme

:package: knex-model

A wrapper around the Knex library using ES6 classes.

Description

This package hands over BREAD-like methods by wrapping the Knex library. It does so by providing a base class (ES6, yay!) that you can extend and use on your own models.

Install

# npm
npm i --save @ruanmartinelli/knex-model

# yarn
yarn add @ruanmartinelli/knex-model

Usage

Assuming you already have Knex configured, it's fairly simple to setup everything up:

import conn from './database' // Your knex connection
import Model from '@ruanmartinelli/knex-model'

// Configure your options based on your model:
const opts = {
  tableName: 'book',
  connection: conn
}

// Declare your model:
class BookModel extends Model {
  constructor(options) {
    super(options)
  }
}
// *don't forget to extend the Model class

// Create a new instance of BookModel by passing the options:
const Book = new BookModel(opts)

After that, the Book instance will inherit the following methods:

// ...

// Find books based on a filter
Book.find(filter)

// Find a single book based on an ID
Book.findById(42)

// Returns the total number of books
Book.count()

// Create a new book and return it
Book.insert(book)

// Update an existing book and return it
Book.update(book)

// Create or update a new book
Book.upsert(book)

// Deletes a book
Book.remove(42)

For a explanation or each method check the "Methods" section.

API

Options

You can customize your models by tweaking the options object.

options.tableName (required)

Type: string

Name of the table associated with the model.

options.connection (required)

A Knex connection object.

options.columns

Type: Array<string>

Array of column names. If none is supplied, it will use <tableName>.*.

options.joins

Type: Array<string> | Array<object>

Array of join statements.

Strings will be called using the .joinRaw() method.

Objects must have a "table", "first" and "second" attributes and only support INNER JOIN operations. See more on the full example below.

options.idAttribute

Type: string

Name of the primary key in table. The default will be 'id' if none is supplied.

options.customFilters

Type: object

An object with custom filter functions that can be used in the .find() method. See more on the full example below.

options.groupBy

Type: Array<string>

An array with the columns to group by.

Hooks

The following hooks are supported:

options.beforeInsert

options.afterInsert

options.afterUpdate

options.beforeUpdate

Type: Function

Function that will be called with the argument received by the .update() or .insert() methods.

Full Example

{
  // Required ⚠️
  // Name of the table related to the model.
  tableName: 'book',

  // Required ⚠️
  // A knex connection object.
  connection: knex(config),

  // Declare the columns that will be fetch from the table.
  columns: [
    'book.*',
    'author.name as author_name',
    'author.id as author_id'
  ],

  // Inner joins can be performed by passing an object.
  // If you need sophisticated joins just write them as a string.
  joins: [
    // Inner Join using an object:
    { table:'author' first: 'author.id', second: 'book.id_author' },

    // Or use a string for other types of join:
    'LEFT OUTER JOIN editor on editor.id = booking.id_editor'
  ],

  // Whatever name you use on your table to reference the Primary key.
  // By default the value is 'id'.
  idAttribute: 'id',

  customFilters: {
    // The "query" param is the interface provided by Knex to build queries.
    // See here: http://knexjs.org/#Builder-knex
    // The "value" param has the value for what was passed to the filter on the .find() method.
    // Eg.:
    // If we call:
    //
    //     Book.find({ mainCharacterName: 'Kvothe' })
    //
    // Then the "value" param on the function above will hold the value 'Kvothe'.
    mainCharacterName: (query, value) => {
      if(!typeof value === 'string') throw ValidationError('Character name must be a string!!')

      query.join('main_character', 'main_character.book_id', 'book.id')
      query.where('main_character.name', value)
    }
  },

  // Columns to group by in query
  groupBy: ['book.id']

  // Hooks are called with the values passed to the .insert() and .update() methods.
  // You can use them to validate your objects, for example:
  beforeInsert: (book) => validateBook(book),
  beforeUpdate: (book) => validateBook(book)
}

Methods

After instantiating a new model you will be able to call any of the methods bellow.

Note: all methods return a Promise object.

.find([filter])

Returns an Array of objects based on the filter.

The .find() method expects a filter object. The keys in this object should either a name of a column or a custom filter.

Example:

// Suppose that the "book" table has the following columns:
//   id, title, isbn, publish_date, id_author, id_editor

// Query by the column names:
Book.find({ isbn: '...' })

Book.find({ title: '', publish_date: '...' })

// Query with custom filters:
Book.find({ mainCharacterName: 'Kvothe' })

// This fails:
Book.find({ not_a_column_nor_a_custom_filter: '...' })

.findById(id)

Returns an object from the table based on the id.

This method is an alias for calling .find() with an { id } filter and returning the first result.

.insert(model)

Inserts an object on table and returns it.

.update(model)

Updates an object on the table and returns it.

This method expects the object to have an id field present (or the key defined on options.idAttribute).

.upsert(model)

Updates or inserts an object on the table and returns it.

If the object has an id, it will be updated. If it doesn't, a new object will be created.

.remove(id)

Returns true.

Remove an object from table based on its id.

.count()

Returns the number of rows on the table.

Custom Methods

This library doesn't try to abstract away the Knex interface or prevent you from writing SQL queries.

If you need to create your own custom method or overwrite any of the provided (actually this is not advised), just write it inside of your model declaration:

class Book extends Model {
  constructor(options) {
    super(options)
  }

  someVeryCustomQuery() {
    // You can use the "knex" instance inherited from the Model class
    return this.knex('book')
      .select('*')
      .where('title', 'like', '%Bananas%')
  }
}

License

MIT © Ruan Martinelli