UNPKG

8.07 kBMarkdownView Raw
1# [![Fortune.js](https://fortunejs.github.io/fortune/assets/fortune_logo.svg)](http://fortune.js.org)
2
3[![Build Status](https://img.shields.io/travis/fortunejs/fortune/master.svg?style=flat-square)](https://travis-ci.org/fortunejs/fortune)
4[![npm Version](https://img.shields.io/npm/v/fortune.svg?style=flat-square)](https://www.npmjs.com/package/fortune)
5[![License](https://img.shields.io/npm/l/fortune.svg?style=flat-square)](https://raw.githubusercontent.com/fortunejs/fortune/master/LICENSE)
6
7Fortune.js is a non-native graph [database abstraction layer](https://en.wikipedia.org/wiki/Database_abstraction_layer) that implements graph-like features on the application-level for Node.js and web browsers. It provides a common interface for databases, as well as relationships, inverse updates, referential integrity, which are built upon assumptions in the data model.
8
9It's particularly useful for:
10
11- Bi-directional relationships in any database.
12- Applications that need storage options to be portable.
13- Sharing the same data models on the server and client.
14
15[View the website](http://fortune.js.org) for documentation. Get it from `npm`:
16
17```sh
18$ npm install fortune --save
19```
20
21*This is the core module. Additional features such as networking (HTTP, WebSocket), database adapters, serialization formats are listed in the [plugins page](http://fortune.js.org/plugins).*
22
23
24## Usage
25
26Only record type definitions need to be provided. These definitions describe what data types may belong on a record and what relationships they may have, for which Fortune.js does inverse updates and maintains referential integrity. Here's an example of a basic micro-blogging service:
27
28```js
29const fortune = require('fortune') // Works in web browsers, too.
30
31const store = fortune({
32 user: {
33 name: String,
34
35 // Following and followers are inversely related (many-to-many).
36 following: [ Array('user'), 'followers' ],
37 followers: [ Array('user'), 'following' ],
38
39 // Many-to-one relationship of user posts to post author.
40 posts: [ Array('post'), 'author' ]
41 },
42 post: {
43 message: String,
44
45 // One-to-many relationship of post author to user posts.
46 author: [ 'user', 'posts' ]
47 }
48})
49```
50
51Note that the primary key `id` is reserved, so there is no need to specify this. Links are `id`s that are maintained internally at the application-level by Fortune.js, and are always denormalized so that every link has a back-link. What this also means is that changes in a record will affect the links in related records.
52
53By default, the data is persisted in memory (and IndexedDB for the browser). There are adapters for databases such as [MongoDB](https://github.com/fortunejs/fortune-mongodb), [Postgres](https://github.com/fortunejs/fortune-postgres), and [NeDB](https://github.com/fortunejs/fortune-nedb). See the [plugins page](http://fortune.js.org/plugins/) for more details.
54
55Fortune has 4 main methods: `find`, `create`, `update`, & `delete`, which correspond to [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete). The method signatures are as follows:
56
57```js
58// The first argument `type` is always required. The optional `include`
59// argument is used for finding related records in the same request and is
60// documented in the `request` method, and the optional `meta` is specific to
61// the adapter. All methods return promises.
62store.find(type, ids, options, include, meta)
63store.create(type, records, include, meta) // Records required.
64store.update(type, updates, include, meta) // Updates required.
65store.delete(type, ids, include, meta)
66
67// For example...
68store.find('user', 123).then(results => { ... })
69```
70
71The first method call to interact with the database will trigger a connection to the data store, and it returns the result as a Promise. The specific methods wrap around the more general `request` method, see the [API documentation for `request`](http://fortune.js.org/api/#fortune-request).
72
73
74## Input and Output Hooks
75
76I/O hooks isolate business logic, and are part of what makes the interface reusable across different protocols. An input and output hook function may be defined per record type. Hook functions accept at least two arguments, the `context` object, the `record`, and optionally the `update` object for an `update` request. The method of an input hook may be any method except `find`, and an output hook may be applied on all methods.
77
78An input hook function may optionally return or resolve a value to determine what gets persisted, and it is safe to mutate any of its arguments. The returned or resolved value must be the record if it's a create request, the update if it's an update request, or anything (or simply `null`) if it's a delete request. For example, an input hook function for a record may look like this:
79
80```js
81function input (context, record, update) {
82 switch (context.request.method) {
83 // If it's a create request, return the record.
84 case 'create': return record
85
86 // If it's an update request, return the update.
87 case 'update': return update
88
89 // If it's a delete request, the return value doesn't matter.
90 case 'delete': return null
91 }
92}
93```
94
95An output hook function may optionally return or resolve a record, and it is safe to mutate any of its arguments.
96
97```js
98function output (context, record) {
99 record.accessedAt = new Date()
100 return record
101}
102```
103
104Based on whether or not the resolved record is different from what was passed in, serializers may decide not to show the resolved record of the output hook for update and delete requests.
105
106Hooks for a record type may be defined as follows:
107
108```js
109const store = fortune({
110 user: { ... }
111}, {
112 hooks: {
113 // Hook functions must be defined in order: input first, output last.
114 user: [ input, output ]
115 }
116})
117```
118
119
120## Networking
121
122There is a [HTTP listener implementation](https://github.com/fortunejs/fortune-http), which returns a Node.js request listener that may be composed within larger applications. It maps Fortune requests and responses to the HTTP protocol automatically:
123
124```js
125// Bring your own HTTP! This makes it easier to add SSL and allows the user to
126// choose between different HTTP implementations, such as HTTP/2.
127const http = require('http')
128const fortune = require('fortune')
129const fortuneHTTP = require('fortune-http')
130
131const store = fortune(...)
132
133// The `fortuneHTTP` function returns a listener function which does
134// content negotiation, and maps the internal response to a HTTP response.
135const listener = fortuneHTTP(store)
136const server = http.createServer((request, response) =>
137 listener(request, response)
138 .catch(error => { /* error logging */ }))
139
140store.connect().then(() => server.listen(1337))
141```
142
143This yields an *ad hoc* JSON over HTTP API, as well as a HTML interface for humans. There are also serializers for [Micro API](https://github.com/fortunejs/fortune-micro-api) (JSON-LD) and [JSON API](https://github.com/fortunejs/fortune-json-api).
144
145Fortune.js implements its own [wire protocol](https://github.com/fortunejs/fortune-ws) based on [WebSocket](https://developer.mozilla.org/docs/Web/API/WebSockets_API) and [MessagePack](http://msgpack.org), which is useful for soft real-time applications.
146
147
148## Features and Non-Features
149
150- Inverse relationship updates, automatically maintain both sides of relationships between records.
151- Referential integrity, ensure that links must be valid at the application level.
152- Type validations, fields are guaranteed to belong to a single type.
153- Adapter interface, use any database that can implement an adapter.
154- **No** object-relational mapping (ORM) or active record pattern, just plain data objects.
155- **No** coupling with network protocol, handle requests from anywhere.
156
157
158## Requirements
159
160Fortune.js is written in ECMAScript 5.1, with one ECMAScript 6 addition: **Promise**. Most of its public API returns Promises to be compatible with future editions of the language.
161
162
163## License
164
165This software is licensed under the [MIT license](https://raw.githubusercontent.com/fortunejs/fortune/master/LICENSE).