Loading...
'use strict';
const Fractale = require('fractale');
const KeyValuePair = Fractale.create(
'KeyValuePair', /* Name of your model (required) */
{ /* Model's schema */
key: String,
value: undefined,
}
);
/* More complete example */
const Model = Fractale.create(
'Model',
{
mixed: undefined,
boolean: Boolean,
number: Number,
string: String,
date: Date,
boards: [String],
metadata: { key: String },
inception: KeyValuePair,
collection: [{ key: String, value: null }],
self: Fractale.SELF, // the Model itself
}
);
/* Full example */
const Full = Fractale.create(
'Full',
Model, // Full inherit Model
{
declareAfter: Fractale.from('After'),
withOption: Fractale.with(String, { validator: { in: ['Foo','Bar'] } }),
}
);
const After = Fractale.create('After', {
start: Fractale.with(Date, { required: true, default: '2000-01-01' }),
end: Date,
});
const instance = new Model({
mixed: 'Great !',
boolean: true,
number: 42,
string: 'Hello world',
boards: ['Lorem ipsum', 'dolores sit amet'],
metadata: { key: 'AZERTYUIOP' },
inception: { key: 'key', value: 1 },
collections: [
{ key: 'foo', value: 123 },
{ key: 'bar', value: 456 }
]
});
console.log(instance.serialize());
/*
> {
mixed: 'Great !',
boolean: true,
number: 42,
string: 'Hello world',
boards: ['Lorem ipsum', 'dolores sit amet'],
metadata: { key: 'AZERTYUIOP' },
inception: { key: 'key', value: 1 },
collections: [
{ key: 'foo', value: 123 },
{ key: 'bar', value: 456 }
]
}
*/
/* Copy props to another instance */
// Method 1
const full = Full.from(instance);
// Method 2
const serialized = instance.serialize();
delete serialized.uuid;
const clone = new Full(serialized);
console.log(instance.mixed); // > true
instance.mixed = 123;
console.log(instance.mixed); // > 123
console.log(instance.boolean); // > true
instance.boolean = false;
console.log(instance.boolean); // > false
console.log(instance.number); // > 42
instance.number = 12;
console.log(instance.number); // > 12
console.log(instance.string); // > 'Hello world'
instance.string = 'Lorem ipsum';
console.log(instance.string); // > 'Lorem ipsum'
console.log(instance.boards[0]); // > 'Lorem ipsum'
instance.boards[0] = 'Hello world';
console.log(instance.boards[0]); // > 'Hello World'
console.log(instance.metadata.key); // > 'AZERTYUIOP'
instance.metadata.key = 'foo';
console.log(instance.metadata.key); // > 'foo'
console.log(instance.inception); // > KeyValuePair { key: 'key', value: 1 }
instance.inception = new KeyValuePair({ key: 'new_key', value: 'new_value' });
console.log(instance.inception); // > KeyValuePair { key: 'new_key', value: 'new_value' }
console.log(instance.inception); // > KeyValuePair { key: 'new_key', value: 'new_value' }
instance.inception.value = 'updated_value';
console.log(instance.inception); // > KeyValuePair { key: 'new_key', value: 'updated_value' }
console.log(instance.collections[0].key); // > 'foo'
instance.collections[0].key = 'pass';
instance.collections[0] = { value: 789 };
console.log(instance.collections[0].key); // > 'pass'
console.log(instance.collections[0].value); // > 789
console.log(instance.serialize());
/*
> {
mixed: 123,
boolean: false,
number: 12,
string: 'Lorem ipsum',
boards: ['Hello world', 'dolores sit amet'],
metadata: { key: 'foo' },
collections: [
{ key: 'pass', value: 789 },
{ key: 'bar', value: 456 }
],
inception: { key: 'new_key', value: 'updated_value' }
}
*/
/* Array methods use */
instance.collections.push({ key: 'azertyuiop', value: 2 });
instance.collections = instance.collections.concat([{ key: 'new_key', value: 3 }, { key: 'N3W_K3Y', value: 4 }]);
console.log(instance.serialize().collections);
/*
> [
{ key: 'pass', value: 789 },
{ key: 'bar', value: 456 },
{ key: 'qwerty', value: 1 },
{ key: 'new_key', value: 3 },
{ key: 'N3W_K3Y', value: 4 }
]
*/
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
const Simple = Fractale.create("Simple", {
mixed: undefined,
boolean: Boolean,
number: Number,
bigint: BigInt,
string: String,
color: Color,
date: Date,
regexp: RegExp,
buffer: ArrayBuffer,
int8: Int8Array,
uint8: Uint8Array,
"uint8_clamped": Uint8ClampedArray,
int16: Int16Array,
uint16: Uint16Array,
int32: Int32Array,
uint32: Uint32Array,
float32: Float32Array,
float64: Float64Array,
bigint64: BigInt64Array,
biguint64: BigUint64Array
});
const { Simple } = module.exports.get();
const instance = new Simple({
mixed: 'It\'s dangerous to go alone! Take this.',
buffer: 'RnJhY3RhbGUgYnVmZmVyIHNhdmU=',
int8: 'RnJhY3RhbGUgSW50OEFycmF5IHNhdmU=',
uint8: 'RnJhY3RhbGUgVWludDhBcnJheSBzYXZl',
uint8_clamped: 'RnJhY3RhbGUgVWludDhDbGFtcGVkQXJyYXkgc2F2ZQ==',
int16: 'RnJhY3RhbGUgSW50MTZBcnJheSBzYXZl',
uint16: 'RnJhY3RhbGUgVWludDE2QXJyYXkgdW5pdCB0ZXN0',
int32: 'RnJhY3RhbGUgSW50MzJBcnJheSB0ZXN0',
uint32: 'RnJhY3RhbGUgVUludDMyQXJyYXkgdGVzdGluZw==',
float32: 'RnJhY3RhbGUgRmxvYXQzMkFycmF5IHVuaXRzIHRlc3Q=',
float64: 'RnJhY3RhbGUgRmxvYXQ2NEFycmF5IHVuaXRzIHRlc3Q=',
bigint64: 'RnJhY3RhbGUgQmlnSW50NjRBcnJheSB1bml0IHRlc3Q=',
biguint64: 'RnJhY3RhbGUgQmlnVUludDY0QXJyYXkgdGVzdGluZ3M=',
});
_.test(instance.mixed, 'It\'s dangerous to go alone! Take this.', 'Error on simple accessor with type mixed');
_.test(instance.boolean, false, 'Error on simple accessor with type boolean');
_.test(instance.number, 31, 'Error on simple accessor with type number');
_.test(instance.bigint, 31n, 'Error on simple accessor with type bigint');
_.test(instance.string, 'Lorem ipsum', 'Error on simple accessor with type string');
_.test(instance.color.hex(), '#AA0000', 'Error on simple accessor with type color');
_.test(instance.date.format('DD/MM/YYYY'), '01/01/2000', 'Error on simple accessor with type date');
_.test(instance.regexp.toString(), /toto/g.toString(), 'Error on simple accessor with type bigint');
_.test(base64.encode(instance.buffer), 'RnJhY3RhbGUgYnVmZmVyIHNhdmU=', 'Error on simple accessor with type buffer');
_.test(base64.encode(instance.int8.buffer), 'RnJhY3RhbGUgSW50OEFycmF5IHNhdmU=', 'Error on simple accessor with type int8');
_.test(base64.encode(instance.uint8.buffer), 'RnJhY3RhbGUgVWludDhBcnJheSBzYXZl', 'Error on simple accessor with type uint8');
_.test(base64.encode(instance.uint8_clamped.buffer), 'RnJhY3RhbGUgVWludDhDbGFtcGVkQXJyYXkgc2F2ZQ==', 'Error on simple accessor with type uint8_clamped');
_.test(base64.encode(instance.int16.buffer), 'RnJhY3RhbGUgSW50MTZBcnJheSBzYXZl', 'Error on simple accessor with type int16');
_.test(base64.encode(instance.uint16.buffer), 'RnJhY3RhbGUgVWludDE2QXJyYXkgdW5pdCB0ZXN0', 'Error on simple accessor with type uint16');
_.test(base64.encode(instance.int32.buffer), 'RnJhY3RhbGUgSW50MzJBcnJheSB0ZXN0', 'Error on simple accessor with type int32');
_.test(base64.encode(instance.uint32.buffer), 'RnJhY3RhbGUgVUludDMyQXJyYXkgdGVzdGluZw==', 'Error on simple accessor with type uint32');
_.test(base64.encode(instance.float32.buffer), 'RnJhY3RhbGUgRmxvYXQzMkFycmF5IHVuaXRzIHRlc3Q=', 'Error on simple accessor with type float32');
_.test(base64.encode(instance.float64.buffer), 'RnJhY3RhbGUgRmxvYXQ2NEFycmF5IHVuaXRzIHRlc3Q=', 'Error on simple accessor with type float64');
_.test(base64.encode(instance.bigint64.buffer), 'RnJhY3RhbGUgQmlnSW50NjRBcnJheSB1bml0IHRlc3Q=', 'Error on simple accessor with type bigint64');
_.test(base64.encode(instance.biguint64.buffer), 'RnJhY3RhbGUgQmlnVUludDY0QXJyYXkgdGVzdGluZ3M=', 'Error on simple accessor with type biguint64');
instance.mixed = -1;
instance.boolean = true;
instance.number = 42;
instance.bigint = 42n;
instance.string = 'Dolor sit amet';
instance.color = 'rgba(0, 0, 255, 0)';
_.test(instance.mixed, -1, 'Error on simple accessor with type mixed after change');
_.test(instance.boolean, true, 'Error on simple accessor with type boolean after change');
_.test(instance.number, 42, 'Error on simple accessor with type number after change');
_.test(instance.bigint, 42n, 'Error on simple accessor with type number after change');
_.test(instance.string, 'Dolor sit amet', 'Error on simple accessor with type string after change');
_.test(instance.color.hex(), '#0000FF00', 'Error on simple accessor with type string after change');
resolve(instance);
{
"uuid": "764a4649-6de0-4ae3-ab0c-7009cc16fcc8",
"mixed": -1,
"boolean": true,
"number": 42,
"bigint": "42",
"string": "Dolor sit amet",
"color": "#0000FF00",
"date": "2000-01-01T02:00:00.000Z",
"regexp": "/toto/g",
"buffer": "RnJhY3RhbGUgYnVmZmVyIHNhdmU=",
"int8": "RnJhY3RhbGUgSW50OEFycmF5IHNhdmU=",
"uint8": "RnJhY3RhbGUgVWludDhBcnJheSBzYXZl",
"uint8_clamped": "RnJhY3RhbGUgVWludDhDbGFtcGVkQXJyYXkgc2F2ZQ==",
"int16": "RnJhY3RhbGUgSW50MTZBcnJheSBzYXZl",
"uint16": "RnJhY3RhbGUgVWludDE2QXJyYXkgdW5pdCB0ZXN0",
"int32": "RnJhY3RhbGUgSW50MzJBcnJheSB0ZXN0",
"uint32": "RnJhY3RhbGUgVUludDMyQXJyYXkgdGVzdGluZw==",
"float32": "RnJhY3RhbGUgRmxvYXQzMkFycmF5IHVuaXRzIHRlc3Q=",
"float64": "RnJhY3RhbGUgRmxvYXQ2NEFycmF5IHVuaXRzIHRlc3Q=",
"bigint64": "RnJhY3RhbGUgQmlnSW50NjRBcnJheSB1bml0IHRlc3Q=",
"biguint64": "RnJhY3RhbGUgQmlnVUludDY0QXJyYXkgdGVzdGluZ3M="
}
Inspired from Mongoose, it allows you to modeling your data to be explicit on data format.
It will test value of each fields and link model between them.
npm install --save fractale
You can found more documentation and examples here or wiki.
Usage of uuid to generate a unique id for model instances.
Optional :
Usage of moment for date.
Usage of teinte for color.
Usage of mongoose for bridge / provider.
Usage of prop-types for bridge.
Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. Please make sure to update tests as appropriate.
See the contributing and code of conduct files for details
This project is licensed under the MIT License - see the LICENSE file for details
Jocelyn Faihy - Web developer and Blob of Internets - Jochlain
See also the list of contributors who participated in this project.
Fractale add other custom types which need other optional modules
Need npm i -S teinte
const Colored = Fractale.create('Colored', {
color: Fractale.Color
});
const colored = new Colored({ color: '#0f0f0f' });
console.log(colored.hsl());
If moment module is installed Date will be automatically transform to moment instance
Need npm i -S moment
const Article = Fractale.create('Article', {
content: String,
created_at: Date,
updated_at: Date,
});
const article = new Article({
content: 'This module is awesome',
created_at: '2000-01-01',
updated_at: '2000-01-01',
});
console.log(article.created_at.format('DD/MM/YYYY'));
'use strict';
const Fractale = require('fractale');
Fractale.setOptions({
use_moment: () => { try { require('moment'); return true; } catch (error) { return false; }}, // Specify to fractale to transform date to moment instance
});
'use strict';
const Fractale = require('fractale');
const Child = Fractale.create('Child', {
mixed: undefined,
boolean: Boolean,
number: Number,
string: String,
});
const Parent = Fractale.create('Parent', Child, {
parent: Fractale.with(Fractale.SELF, {
// Pass number of parent to number of great-parent
through: ['number'],
}),
children: [
Fractale.with(Child, {
// Pass number of parent to mixed of child
// Pass string of parent to string of child
through: { number: 'mixed', string: 'string' },
})
],
});
'use strict';
const Fractale = require('fractale');
const Simple = Fractale.create('Simple', {
anyway: Fractale.with(undefined, {
validator: (value) => value !== 'A value'
}),
mixed: Fractale.with(undefined, {
validator: {
in: ['foo', 'bar', 42]
}
}),
number: Fractale.with(Number, {
validator: {
gt: 17,
gte: 18,
lt: 51,
lte: 50,
between: [18, 50]
}
}),
date: Fractale.with(Date, {
validator: {
gt: '2019-11-17',
gte: new Date('2019-11-18'),
lte: moment('2019-11-20'),
lt: moment(),
between: [18] // If one value is between ... and today or today and ...
}
}),
string: Fractale.with(String, {
validator: {
like: /bar$/
}
}),
});
From a JSON of 10.45M:
Deserialization: ~0.895s => 11.68Mo/s
Read: ~0.001s
Serialization: ~0.304s => 34.37Mo/s
From a JSON of 339.06M:
Deserialization: ~3.301s => 102.71Mo/s
Read: ~0.001s
Serialization: ~1.173s => 289.05Mo/s
From a JSON of 1.27G:
Deserialization: ~12.942s => 98.22Mo/s
Read: ~0s
Serialization: ~6.089s => 208.77Mo/s
Fractale lets you possibility to save and retrieve values in a storage
// To use Web localStorage
Fractale.memory.setProvider('local');
// To use Web sessionStorage
Fractale.memory.setProvider('session');
// To use Web cookie
Fractale.memory.setProvider('cookie', { expires: 6048e5 });
// To use Web IndexedDB
Fractale.memory.setProvider('idb', { database: 'Æ’_database' });
const model = Model.toMongoose();
const propTypes = Model.toPropTypes();
const Inheritance_Child = Fractale.create("Inheritance_Child", {
value: String
});
const Inheritance_Parent = Fractale.create("Inheritance_Parent", Inheritance_Child, {
children: [
Inheritance_Child
]
});
const { Inheritance_Parent } = module.exports.get();
const instance = new Inheritance_Parent({
value: 'Hello',
children: [
{ value: 'world' },
{ value: 'you' },
]
});
_.test(instance.sayHelloTo(0), 'Hello world', `Expected "Hello world" got "${instance.sayHelloTo(0)}"`);
_.test(instance.sayHelloTo(1), 'Hello you', 'Error on parent method call');
_.test(instance.toUpperCase(), 'HELLO', 'Error on method inheritance');
resolve(instance);
{
"uuid": "095ee570-53b7-418e-856d-1cb869b7f8cd",
"value": "Hello",
"children": [
{
"uuid": "d01623e5-8c49-4fc9-b7a8-94ae79a87dff",
"value": "world"
},
{
"uuid": "2c54c27b-b05b-4344-9e49-29985e8b8383",
"value": "you"
}
]
}
const Inception_Parent = Fractale.create("Inception_Parent", {
value: String
});
const Inception_Child = Fractale.create("Inception_Child", {
parent: Inception_Parent,
value: String
});
const { Inception_Child } = module.exports.get();
const child = new Inception_Child({
parent: { value: 'foo' },
value: 'bar',
});
_.test(child.parent.value, 'foo', 'Error on inception setter with dot');
const parent = child.parent;
const value = 'hello world';
parent.value = value;
_.test(child.parent.value, value, 'Error on inception setter with dot');
child.parent.value = 'foo';
_.test(child.parent.value, 'foo', 'Error on deep setter with dot');
resolve(child);
{
"uuid": "d2dd4dd1-f369-4ed8-821e-5040deed075b",
"parent": {
"uuid": "33ba3961-cc86-4dbc-9945-b0691bd36d93",
"value": "foo"
},
"value": "bar"
}
const Metadata = Fractale.create("Metadata", {
metadata: {
key: String,
data: {
key: String,
value: undefined
}
}
});
const { Metadata } = module.exports.get();
const instance = new Metadata({
metadata: { key: 'Foo', data: { key: 'Bar', value: 12 } }
});
_.test(instance.metadata.key, 'Foo', 'Error on metadata accessor');
const metadata = instance.metadata;
metadata.key = 'decomposition';
_.test(instance.metadata.key, 'decomposition', 'Error on metadata accessor with decomposition');
instance.metadata.key = 'dot';
_.test(instance.metadata.key, 'dot', 'Error on metadata accessor with dot');
instance.metadata = { key: 'assign' };
_.test(instance.metadata.key, 'assign', 'Error on metadata accessor with assign');
_.test(instance.metadata.data.key, 'Bar', 'Error on metadata accessor with assign');
instance.metadata = { data: { key: 'after', value: 13 } };
_.test(instance.metadata.key, 'assign', 'Error on metadata accessor with bracket');
_.test(instance.metadata.data.key, 'after', 'Error on metadata accessor with bracket');
_.test(instance.metadata.data.value, 13, 'Error on metadata accessor with bracket');
resolve(instance);
{
"uuid": "6c63fcf6-323a-4cb7-8bd1-afdb4d73c086",
"metadata": {
"uuid": "daf1d856-b57c-41a7-9a5e-407188f5f24f",
"key": "assign",
"data": {
"uuid": "c22f5b47-3434-45cb-86e7-fba5134347d5",
"key": "after",
"value": 13
}
}
}
const Self = Fractale.create("Self", {
self: Self,
value: String
});
const { Self } = module.exports.get();
const instance_1 = new Self({ value: 'foo' });
const instance_2 = new Self({ self: { self: instance_1, value: 'bar' }, value: 'hello' });
_.test(instance_1.value, 'foo', 'Error on deep accessor variable name');
_.test(instance_2.self.value, 'bar', 'Error on self-reference accessor');
_.test(instance_2.self.self.value, 'foo', 'Error on double self-reference accessor');
_.test(instance_2.self.self.self, undefined, 'Error infinite self-reference accessor');
resolve(instance_2);
{
"uuid": "9ad98dd3-6e65-41e0-a592-998c68aafe95",
"self": {
"uuid": "3365521f-4db8-4856-a5a2-5dacda8648ba",
"self": {
"uuid": "49e72f5e-faa3-4948-a162-3f4abdb792f6",
"value": "foo"
},
"value": "bar"
},
"value": "hello"
}
const Collection_Item = Fractale.create("Collection_Item", {
value: String
});
const Collection_Category = Fractale.create("Collection_Category", {
items: [
Collection_Item
]
});
const { Collection_Category, Collection_Item } = module.exports.get();
const item = new Collection_Item({ value: 'foo' });
const category = new Collection_Category({ items: [item, { value: 'bar' }] });
_.test(category.items[0].value, 'foo', 'Error on collection accessor with brace');
_.test(category.items[1].value, 'bar', 'Error on collection accessor with brace');
let changed = false;
category.addEventListener('change', () => changed = true);
category.items[0].value = 'hello';
if (!changed) {
throw new Error('Error on collection change event');
}
_.test(category.items[0].value, 'hello', 'Error on collection accessor with brace after change');
_.test(category.items.first.value, 'hello', 'Error on collection method first accessor');
category.items.push({ value: 'world' });
_.test(category.items.last.value, 'world', 'Error on collection method last accessor');
_.test(category.items.map(item => item.value).join(', '), 'hello, bar, world', 'Error on array method map accessor');
_.test(category.items.filter(item => item.value === 'hello').map(item => item.value).join(', '), 'hello', 'Error on array method filter accessor');
_.test(category.items.reduce((accu, item) => `${accu} ${item.value}`, '').trim(), 'hello bar world', 'Error on array method reduce accessor');
category.items.remove(item);
if (category.items.length !== 2) throw new Error('Error on array method remove accessor');
resolve(category);
{
"uuid": "269189c4-9f16-47db-bfe0-094ed8a2a676",
"items": [
{
"uuid": "6edf2663-1fb9-4b76-8c4d-724f5ef70da1",
"value": "bar"
},
{
"uuid": "522ec9e9-2920-415d-a239-79fb620227fa",
"value": "world"
}
]
}
const Global_Options = Fractale.create("Global_Options", {
transformed: Number
});
const { Global_Options } = module.exports.get();
const instance = new Global_Options({
transformed: 39,
});
_.test(instance.transformed, 39, 'Error on global option transform accessor with type percentage');
instance.transformed = '10%';
_.test(instance.transformed, 0.1, 'Error on global option transform accessor with type percentage');
resolve(instance);
{
"uuid": "325dda13-7f10-4bc1-a212-c7eaa7e9beb6",
"transformed": 0.1
}
const Form_Parent = Fractale.create("Form_Parent", {
value: String
});
const Form_Child = Fractale.create("Form_Child", {
parent: Form_Parent,
value: String
});
const { Form_Parent, Form_Child } = module.exports.get();
const parent = new Form_Parent({ value: 'foo' });
const child = new Form_Child({ parent: parent.uuid, value: 'bar' });
_.test(child.value, 'bar', 'Error on form setter');
_.test(child.parent.value, 'foo', 'Error on form setter');
resolve(child);
{
"uuid": "250940e8-d1a4-4476-89e9-fcc882f55c64",
"parent": {
"uuid": "ab7cde95-30ed-4bdf-8872-0b03a537e3a2",
"value": "foo"
},
"value": "bar"
}
const ModelWithRegExpAsKey = Fractale.create("ModelWithRegExpAsKey", {
"/item_\\d+/i": String
});
const { ModelWithRegExpAsKey } = module.exports.get();
const instance = new ModelWithRegExpAsKey({
item_1: 'Foo',
item_2: 'Bar',
});
_.test(instance.item_1, 'Foo', 'Error on regexp key accessor with type string');
_.test(instance.item_2, 'Bar', 'Error on regexp key accessor with type string');
resolve(instance);
{
"uuid": "1e35cacd-193c-4cff-bbbb-d687f6023426",
"item_1": "Foo",
"item_2": "Bar"
}