Skip to content

Latest commit

 

History

History
185 lines (121 loc) · 8.96 KB

adapter-specification.md

File metadata and controls

185 lines (121 loc) · 8.96 KB

Adapter Interface Reference

The adapter interface specification is currently under active development and may change.

Semantic (interface)

e.g. RestAPI or MySQL

Stability: 3 - Stable

Implementing the basic semantic interface (CRUD) is really a step towards a complete implementation of the Queryable interface, but with some services/datasources, about as far as you'll be able to get using native methods.

By supporting the Semantic interface, you also get the following:

  • if you write a find() function, developers can also use all of its synonyms, including dynamic finders and findOne(). When they're called, they'll automatically be converted into the appropriate criteria object for the basic find() definition in your adapter.
  • as long as you implement basic where functionality (see Queryable below), Waterline can derive a simplistic version of associations support for you. To optimize the default assumptions with native methods, override the appropriate methods in your adapter.

All officially supported Sails.js database adapters implement the Semantic interface.

Class methods
  • Model.create()
  • Model.find()
  • Model.findOne()
  • Model.update()
  • Model.destroy()
Instance methods
  • henry.save()

Queryable (interface)

Stability: 3 - Stable

Query building features are common in traditional ORMs, but not at all a guarantee when working with Waterline. Since Waterline adapters can support services as varied as Twitter, SMTP, and Skype, traditional assumptions around structured data don't always apply.

If query modifiers are enabled, the adapter must support Model.find(), as well as the complete query interface, or, where it is impossible to do so, at least provide helper notices. If coverage of the interace is unfinished, it's still not a bad idea to make the adapter available, but it's important to clearly state the unifinished parts, and consequent limitations, up front. This helps prevent the creation of off-topic issues in Sails/Waterline core, protects developers from unexpected consequences, and perhaps most importantly, helps focus contributors on high-value tasks.

All officially supported Sails.js database adapters implement this interface.

Query modifiers

Query modifiers include filters:

  • where
  • limit
  • skip
  • sort
  • select
  • distinct

Boolean logic:

  • and
  • or
  • not

As well as groupBy and the aggregators:

  • count
  • sum
  • min
  • max
  • average

IN queries: Adapters which implement where should recognize a list of values (e.g. name: ['Gandalf', 'Merlin']) as an IN query. In other words, if name is either of those values, a match occured.

Sub-attribute modifiers: You are also responsible for sub-attribute modifiers, (e.g. { age: { '>=' : 65 } }) with the notable exception of contains, startsWith, and endsWith, since support for those modifiers can be derived programatically by leveraging your definition of like.

  • like (SQL-style, with % wildcards)
  • '>' (you can also opt to use the more verbose .greaterThan(), etc.)
  • '<'
  • '>='
  • '<='
  • TODO: range queries (e.g. { '<':4, >= 2 })

Migratable (interface)

Stability: 2 - Unstable

Adapters which implement the Migratable interface are usually interacting with SQL databases. This interface enables the migrate configuration option on a per-model or adapter-global basis, as well as access to the prototypal/class-level CRUD operations for working with tables.

Adapter methods
  • Adaper.define()
  • Adaper.describe()
  • Adaper.alter()
  • Adaper.drop()
Auto-migration strategies
  • "alter" (default)
  • "drop"
  • "safe"

Semantic-Streamable (interface)

Stability: 1 - Experimental

Background

Communicating with another server via messages/packets is the gold standard of performance-- network latency is the slowest I/O operation computers deal with, yet ironically, the standard methodology used by most developers/frameworks/libraries outside of Node.js is detrimental to performance.

In the Node community, you might say we're in the midst of a bit of an I/O renaissance.

The standard approach to communicating with another server (or a disk) involves loading a message into memory from the source, and then sending the entire object to the destination at once.

This is like trying to transport a heavy bag of gold over a river by wading across with it on your back. Even if you're very strong, with enough gold, you will drown. This is analogous to your server running out of RAM as it buffers data in memory, and the resulting scalability problem.

Using Node streams is a different ball game. It's like splitting up the big bag into smaller containers, then floating them across one by one. This way, no matter how much gold you end up with, you never drown.

A huge advantage of using Node.js is the ease with which you can parse and manipulate streams of data. Instead of pulling an entire dataset into RAM, you can inspect it a little at a time. This unlocks a level of performance that is unachievable using conventional approaches.

The most common use case is taking advantage of the available HTTP response stream to pipe the output byte stream from the database directly back to the user. i.e. to generate a dynamic sitemap, you might need to respond with a huge set of data (far too large to fit in memory on a commodity server) and simultaneously transform it into XML.

Implementation

Implementing the Streaming CRUD interface is actually pretty simple-- you just need to get comfortable with Node.js streams. You can mutate streams as they come in-- you just need to find or design a mapping function designed for streams, where you don't have all the data at once.

Blob (interface)

Stability: 1 - Experimental

e.g. sails-local-fs, sails-s3

Implementing the Blob interface allows you to upload and download binary data (aka files) to the service/database. These "blobs" might be MP3 music files (~5MB) but they could also be data-center backups (~50TB). Because of this, it's crucial that adapters which implement this interface use streams for uploads (incoming, into data source from Sails) and downloads (outgoing, from data source to Sails).

Class methods
  • write()
  • read()

One-Way (interface)

Stability: 1 - Experimental

Adapters which implement one-way messages should do so using send() or a suffixed send*() method. This lets developers know that it's not safe to assume that these operations are reversible. An example of one such adapter is SMTP, for sending email, or APNS for sending Apple push notifications.

Class methods
  • send()

Pubsub (interface)

Stability: 1 - Experimental

Adapters implementing the pubsub interface report changes from the service/database back up to the app.

They should emit an event on the sails object.

Examples:

  • Twitter streaming API (see new tweets as they come in)
  • IRC (see new chats as they come in)
  • Stock prices (visualize the latest market data as soon as it is available)
  • Hardware scanners (see new data as it comes in)