Skip to content

Latest commit

 

History

History
90 lines (74 loc) · 3.59 KB

building-models.md

File metadata and controls

90 lines (74 loc) · 3.59 KB

Building Models

Models in ORMnomnom work slightly differently than most ORMs, in that ORMnomnom models are really Data Access Objects. While individual rows resulting from queries made to the database are still realized as instances of the model class you provide, ORMnomnom does not install any new methods or require any subclassing on your model's part. Indeed, ORMnomnom does not even require that data passed to it be instances of your model class.

To see what this looks like, consider this simple example:

const orm = require('ormnomnom')

class Book {
  constructor ({id, title, publish_date, byline}={}) {
    this.id = id
    this.title = title
    this.publishDate = publish_date
    this.byline = byline
  }
}

const BookObjects = orm(Book, {
  id: { type: 'integer' },
  title: { type: 'string' },
  publish_date: { anyOf: [ { type: 'null' }, { type: 'string', format: 'date' } ], default: null },
  byline: { anyOf: [ { type: 'null' }, { type: 'string' } ], default: null }
})

A model, Book, is defined as a class that accepts an object containing title, publish_date, and byline properties. It does not extend any other classes. A Data Access Object (henceforth known as a DAO) is created by calling orm(Book, {<some properties>}), and assigned to BookObjects.

All querying — creating, reading, updating, and deleting — for the Book model is performed by BookObjects, the DAO for Books. It's important to note that ORMnomnom does not add any methods to Bookeverything is done through BookObjects. Book is used solely to materialize rows, and as a way to infer a table name for the query builder.

By default, ORMnomnom will assume that the table name of a given model is constructor.name.toLowerCase() + 's' – that is, the lowercased, pluralized name of the constructor function passed to ORMnomnom. Additionally, ORMnomnom will assume that the name of the primary key for the table is id. You can read about all of the options ORMnomnom accepts in the DAO reference documentation.

// an example of manually specifying the tableName and primaryKey column name:

class Octopus {
  /* ... */
}

orm(Octopus, {
  tableName: 'octopi',
  primaryKey: 'name'
})

The DAO object is primarily a mechanism for generating QuerySet objects and holding metadata about the model. Queries begin with .filter, .all, .get, .update, or .delete, and represent a single query against the database. Some queries return object instances, others return a count of affected rows. This topic will be covered further in the next section, but for now let's look at a simple query:

const getBook = BookObjects.get({title: 'A Hat Full of Sky'})

This particular query will return a promise for single Book object. It could fail a number of ways: if there are no Book's by that title, it will fail with a BookObjects.NotFound error. If there are multiple books by that name, it will fail with BookObjects.MultipleObjectsReturned. These errors are subclasses of orm.NotFound and orm.MultipleObjectsReturned, respectively, and ultimately are subclasses of Error. The DAO holds references to these classes in order to allow users to more easily determine the origin of a given error.

In the next section, we'll explore the full query API.