Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Constructor changes #166

Merged
merged 3 commits into from
Jan 25, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 14 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,37 +29,32 @@ The `Serializer` abstraction allows for multiple serialization formats, includin
The only necessary input is record type definitions. Record types in Fortune.js are the basic means of modelling data. Let's model a subset of Twitter's functionality:

```js
// store.js
const fortune = require('fortune')

module.exports = fortune()
const store = fortune({
user: {
name: { type: String },

.defineType('user', {
name: { type: String },
// Following and followers are inversely related (many-to-many).
following: { link: 'user', inverse: 'followers', isArray: true },
followers: { link: 'user', inverse: 'following', isArray: true },

// Following and followers are inversely related (many-to-many).
following: { link: 'user', inverse: 'followers', isArray: true },
followers: { link: 'user', inverse: 'following', isArray: true },
// Many-to-one relationship of user posts to post author.
posts: { link: 'post', inverse: 'author', isArray: true }
},
post: {
message: { type: String },

// Many-to-one relationship of user posts to post author.
posts: { link: 'post', inverse: 'author', isArray: true }
})

.defineType('post', {
message: { type: String },

// One-to-many relationship of post author to user posts.
author: { link: 'user', inverse: 'posts' }
// One-to-many relationship of post author to user posts.
author: { link: 'user', inverse: 'posts' }
}
})
```

By default, the data is persisted in memory. 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). Then let's add a HTTP server:

```js
// server.js
const http = require('http')
const fortune = require('fortune')
const store = require('./store')

// The `fortune.net.http` helper function returns a listener function which
// does content negotiation, and maps the internal response to a HTTP response.
Expand Down
5 changes: 5 additions & 0 deletions doc/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
# Changelog


##### 2.0.0 (2016-01-25)
- Breaking change: constructor argument now contains all configuration.
- Breaking change: removed `defineType`, `transform`, `transformInput`, `transformOutput`, and static `create` methods. Deprecated in favor of new constructor object.


##### 1.12.0 (2016-01-24)
- Feature: include entire payloads in change event.
- Fix: update objects should show resulting operations.
Expand Down
33 changes: 17 additions & 16 deletions doc/GETTING_STARTED.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,28 @@ Then create an empty `index.js` file adjacent to the `node_modules` folder, and

```js
const fortune = require('fortune')
const store = fortune()
const store = fortune({ ... })
```

The `fortune` function returns a new instance of Fortune, and accepts a configuration object as an argument. We don't need to pass any arguments to the constructor for now, the defaults should work.
The `fortune` function returns a new instance of Fortune, and accepts a configuration object as an argument.


## Record Types

The only necessary input is record type definitions. Let's start with a basic example:
The only necessary input is type definitions. Let's start with a basic example:

```js
store.defineType('user', {
username: { type: String },
key: { type: Buffer },
salt: { type: Buffer },
group: { link: 'group', inverse: 'users', isArray: true }
})

store.defineType('group', {
name: { type: String },
users: { link: 'user', inverse: 'group', isArray: true }
fortune({
user: {
username: { type: String },
key: { type: Buffer },
salt: { type: Buffer },
group: { link: 'group', inverse: 'users', isArray: true }
},
group: {
name: { type: String },
users: { link: 'user', inverse: 'group', isArray: true }
}
})
```

Expand Down Expand Up @@ -74,7 +75,7 @@ This is a pretty basic implementation using the `crypto` module provided by Node
```js
const methods = fortune.methods, errors = fortune.errors

store.transformInput('user', (context, record, update) => {
function input (context, record, update) {
const request = context.request,
method = request.method,
type = request.type,
Expand Down Expand Up @@ -115,15 +116,15 @@ store.transformInput('user', (context, record, update) => {
return update
})
})
})
}
```

Input transform functions are run before anything gets persisted, so it is safe to throw errors. They may either synchronously return a value, or return a Promise. Note that the `password` field on the record is not defined in the record type, arbitrary fields are not persisted. Updating the password in this example requires a field in the `meta.headers` object, for example `Authorization: "Zm9vYmFyYmF6cXV4"` where the value is the base64 encoded old password.

It may be required to transform outputs as well. In this example, we don't want expose the salt and the key publicly:

```js
store.transformOutput('user', (context, record) => {
function output (context, record) {
// Hide sensitive fields.
delete record.salt
delete record.key
Expand Down
2 changes: 1 addition & 1 deletion lib/adapter/adapters/indexeddb/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function worker () {
var version = (db.version || 1) + 1

db.close()
request = indexedDB.open(name, version)
request = indexedDB.open(data.name, version)
request.onerror = errorReconnection
request.onupgradeneeded = handleUpgrade
request.onsuccess = function (event) {
Expand Down
23 changes: 9 additions & 14 deletions lib/browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ var hasCreateObjectURL = 'URL' in globalObject && 'createObjectURL' in URL
* This class just extends Core with some default serializers and static
* properties.
*/
function Fortune (options) {
if (!(this instanceof Fortune)) return new Fortune(options)
function Fortune (recordTypes, options) {
if (!(this instanceof Fortune)) return new Fortune(recordTypes, options)

if (options === void 0) options = {}

// Try to use IndexedDB first, fall back to memory adapter.
Expand All @@ -51,26 +52,20 @@ function Fortune (options) {
/* eslint-enable no-console */
}

if (!('enforceLinks' in options))
options.enforceLinks = false
if (!('settings' in options))
options.settings = {}

if (!('enforceLinks' in options.settings))
options.settings.enforceLinks = false

this.constructor(options)
this.constructor(recordTypes, options)
}


Fortune.prototype = Object.create(Core.prototype)
assign(Fortune, Core)


Fortune.create = function (options) {
/* eslint-disable no-console */
console.warn('The "Fortune.create" method will be deprecated in future ' +
'major versions.')
/* eslint-enable no-console */
return new Fortune(options)
}


// Assigning the Promise implementation.
Object.defineProperty(Fortune, 'Promise', {
enumerable: true,
Expand Down
Loading