Relation data model for JSON objects
npm install relational-jsonrelational-json makes working with complex data simpler than ever.
npm install relational-json --save
var rJSON = require("relational-json");
and you create a db based on a schema you provide:
var db = rJSON(schema);
----------------------------
relational-json is JSON with conscience.
1. It eliminates data duplication
2. It simplifies data updates (you only ever need to modify data in 1 place, since there are no duplicates)
3. It encapsulates your data, data manipulation logic and restricts certain operations (such as wrong datatype in a given field)
4. It's extremely portable, since the data uses the well-known JSON syntax.
5. It makes no environment assumptions (can be used in browser, on node, etc.)
JSON.stringify() does not work as expected. This is due to infinite nesting, which makes youAlso, relational-json is IE9+ compatible, but cannot be shimmed or polyfilled for older browsers.
------------------------------
``js`
{
tableName: {
primary: "field to use as unique identifier. Field must be in fields object.",
fields: {
fieldName: {
allowNull: "can the value be set to null (true / false)",
dataType: "datatype of the field (string, integer, float, date, time, datetime, boolean)",
defaultValue: "value to use if none provided at creation time"
}
},
extends: {
table: "tableName that is a parent of this table",
localField: "own field that references parent table",
foreignField: "parent table field that localField is matched with"
},
aggregates: [
{
table: "tableName that is aggregated",
alias: "property alias to use for relation",
localField: "local field used to build aggregate relations",
foreignField: "foreign field used in aggregate relation",
cardinality: "(single / many), a single relation provides a direct relation to another object. A many relation creates an array of objects"
}
]
}
}
Table fields can also be written in shorthand. This creates a field that has no defaultValue and cannot be null:
``
tableName: {
fields: {
id: "integer",
name: "string"
}
}
relationship is also reflected in the parent tables' rows, which will contain a property to the child row. This will allow you to traverse your data trees in both directions (up ancestors and down descendants).extends example
`js
var schema = {
Vehicle: {
primary: "id",
fields: {
id: "integer",
year: "integer",
maker: { allowNull: true, dataType: "string" }
}
},
Car: {
primary: "id",
fields: {
id: "integer",
model: "string"
},
extends: { table: "Vehicle", localField: "id", foreignField: "id" }
}
};var db = rJSON(schema);
db.Car.post({
id: 1,
year: 2001,
maker: "Toyota",
model: "Camry"
});
db.Car.get(1);
/* own props
{
id: 1,
model: "Camry"
}
*/
// prototype props
db.Car.get(1).year; // 2001
db.Car.get(1).maker; // "Toyota"
db.Vehicle.get(1);
/*
{
id: 1,
year: 2001,
maker: "Toyota",
Car: {
id: 1,
model: "Camry"
}
}
*/
`#### aggregates
This is a composite relation between tables, not inheritance-based. Concretely, if table A "aggregates" table B, rows from table A will have a property pointing to one row (object) or many rows (array) from table B, based on the relations cardinality.
Unlike
extends, aggregate does not affect the prototype chain.aggregates example (single)
`js
var schema = {
Vehicle: {
primary: "id",
fields: {
id: "integer",
year: "integer",
maker: { allowNull: true, dataType: "string" }
}
},
Client: {
primary: "id",
fields: {
id: "integer",
name: "string",
vehicle_id: { allowNull: true, dataType: "integer" }
},
aggregates: [
{ table: "Vehicle", alias: "Vehicle", localField: "vehicle_id", foreignField: "id", cardinality: "single" }
]
}
};var db = rJSON(schema);
db.Vehicle.post({
id: 1,
year: 2001,
maker: "hyundai"
});
db.Client.post({
id: 2,
name: "bob the builder",
vehicle_id: 1
});
db.Client.get(2);
/*
{
id: 2,
name: "bob the builder",
Vehicle: {
id: 1,
year: 2001,
maker: "hyundai"
}
}
*/
``-------------------------------
object* Table : object
* .meta : object
* .get() ⇒ object | Array.<object>
* .post(d) ⇒ object
* .put(d, pkValue) ⇒ object
* .delete(id) ⇒ object
Table | Name | Type | Description |
| --- | --- | --- |
| name | string | Table's property key in the relational-json database |
| pk | string | name of the Table's primary field |
| primary | string | alias of Table.meta.pk |
| aliasMap | object | hashmap of the the table's rows' properties pointing to other tables in the relational-json database |
| ownRequiredFields | Array.<string> | list of all own required fields, which must have a value at all times |
| allRequiredFields | Array.<string> | list of all required fields, including own & ancestors' required fields |
Table object | Array.<object> - if no argument is provided, it returns an array of all data within the table.Table object - row instance created | Param | Type | Description |
| --- | --- | --- |
| d | object | data bundle, must contain all required fields |
Table object - newly created row | Param | Type | Default | Description |
| --- | --- | --- | --- |
| d | object | | field:value object of data to modify |
| pkValue | \* | d.primary | primary value to find row to modify |
Table object - deleted row | Param | Type | Description |
| --- | --- | --- |
| id | \* | primary field value of row to delete |