Skip to content

Commit dc5437c

Browse files
authored
Merge pull request #1 from CodingCarlos/develop
First version ^^
2 parents a74ed23 + 4dde533 commit dc5437c

File tree

12 files changed

+470
-1
lines changed

12 files changed

+470
-1
lines changed

README.md

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,100 @@
11
# modelate
2-
A data modeling tool for NodeJS
2+
A data modeling tool for NodeJS. It's 100% database agnostic, and 100% customizable.
3+
4+
# How does it work?
5+
Create a model, and turn your objects into that model.
6+
7+
```javascript
8+
var Modelate = require('./index');
9+
10+
var model = {
11+
name: {
12+
type: 'string',
13+
length: {
14+
max: 10,
15+
min: 1
16+
},
17+
value: {
18+
eq: 'Paco'
19+
}
20+
},
21+
age: {
22+
type: 'number',
23+
value: {
24+
max: 95,
25+
min: 18
26+
}
27+
}
28+
}
29+
30+
var user = Modelate('User').model(model);
31+
var data = {
32+
name: 'Paco',
33+
age: 17 // Age does not match with min value
34+
};
35+
36+
var result = user.modelate(data); // => { name: 'Paco }
37+
```
38+
# Validators
39+
Validators are just functions. It will be executed for each property, and return a boolean value indicating if the content match the model requirements or not.
40+
41+
- [Type](#type)
42+
- [Length](#length)
43+
- [Value](#value)
44+
- [Custom function](#custom-function)
45+
46+
## Type
47+
If the data has not the specifed type, validation will fail, and that field will not be added to final validated data.
48+
49+
```javascript
50+
{
51+
type: String // Check if data has a JS type (uses typeof)
52+
}
53+
```
54+
55+
## Length
56+
Check data length. It uses default .length param, so it's valid for so much types.
57+
58+
```javascript
59+
{
60+
length: {
61+
eq: Number, // Exact allowed value
62+
max: Number, // Maximum allowed value
63+
min: Number // Minimum allowed value
64+
}
65+
}
66+
```
67+
68+
## Value
69+
Check data length. It uses default .length param, so it's valid for so much types.
70+
71+
```javascript
72+
{
73+
value: {
74+
eq: String || Number, // Exact allowed value (equals)
75+
max: Number, // Maximum allowed value
76+
min: Number, // Minimum allowed value
77+
contains: String || Number // The value contains
78+
}
79+
}
80+
```
81+
82+
## Custom function
83+
Use a custom function to check at your own criteria. The only necessary thing is the function to return true or false-
84+
85+
```javascript
86+
{
87+
func: function A function to validate. Must return true or false.
88+
}
89+
```
90+
91+
The function might look like this:
92+
```
93+
function is42(value) {
94+
var allowed = [42, '42', 'cuarenta y dos', 'fourty two', 'the answer to the life the universe and everything'];
95+
if(allowedValues.indexOf(value) === -1) {
96+
return false;
97+
}
98+
return true;
99+
}
100+
```

index.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/**/
2+
const model = require('./lib/model');
3+
const modelate = require('./lib/modelate');
4+
5+
const models = model.models;
6+
7+
8+
function Modelate(name) {
9+
const self = this;
10+
11+
self.modelName = name;
12+
self.model = model.add;
13+
self.modelate = modelate;
14+
15+
models[name] = {};
16+
17+
return this;
18+
}
19+
20+
21+
module.exports = Modelate;
22+
/*{
23+
add: function () { },
24+
remove: null,
25+
list: null,
26+
modelate: null
27+
};*/
28+

lib/model.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const models = {};
2+
3+
function model(data) {
4+
// ToDo: Validate model
5+
// ToDo: Check if model already exists to merge instead of set
6+
models[this.name] = data;
7+
8+
return this;
9+
}
10+
11+
module.exports = {
12+
models: models,
13+
add: model
14+
};

lib/modelate.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const util = require('./util');
2+
3+
const models = require('./model').models;
4+
const validate = require('./validate');
5+
6+
function modelate(data) {
7+
const model = util.clone(models[this.name]);
8+
9+
for(let prop in model) {
10+
if(validate(data[prop], model[prop])) {
11+
model[prop] = data[prop];
12+
} else {
13+
delete model[prop];
14+
}
15+
}
16+
17+
return model;
18+
}
19+
20+
module.exports = modelate;

lib/util.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/** Deep Copy
2+
* Return a copy of the object passed as param, doing (recursivelly) copys of
3+
* all the objects the initial has.
4+
*
5+
* Caution!!!
6+
* This function is recursive. Copying a very deep object might concern heavy
7+
* performance issues. Use your brain before the function.
8+
*/
9+
function deepCopy(oldObj) {
10+
var newObj = oldObj;
11+
if (oldObj && typeof oldObj === 'object') {
12+
newObj = Object.prototype.toString.call(oldObj) === '[object Array]' ? [] : {};
13+
for (var i in oldObj) {
14+
newObj[i] = deepCopy(oldObj[i]);
15+
}
16+
}
17+
return newObj;
18+
}
19+
20+
/** Merge
21+
* Perform a complete merge of two objects.
22+
*
23+
* Caution!!!
24+
* A third parameter, avoidDeepCopy is also included to avoid creating a deep
25+
* copy of the objects. With this parameter to true, original objects may get
26+
* updated, linked or similar unexpected behaviour.
27+
*/
28+
function merge(old, obj, avoidDeepCopy) {
29+
30+
let dest, orig;
31+
32+
if(avoidDeepCopy) {
33+
dest = old;
34+
orig = obj;
35+
} else {
36+
dest = deepCopy(old);
37+
orig = deepCopy(obj);
38+
}
39+
40+
for(let prop in orig) {
41+
dest[prop] = orig[prop];
42+
}
43+
44+
return dest;
45+
}
46+
47+
48+
module.exports = {
49+
merge: merge,
50+
clone: deepCopy
51+
};

lib/validate.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
// Add validator names here
3+
const validators = ['type', 'length', 'value', 'func'];
4+
5+
// Turn validator names to validator instances.
6+
for(let i = 0; i < validators.length; i++) {
7+
validators[i] = validator(validators[i]);
8+
}
9+
10+
// Validate
11+
function validate(data, model) {
12+
for(let i = 0; i < validators.length; i++) {
13+
if(!validators[i].check(data, model)) {
14+
console.error('Validation for "' + data + '" failed! Reason: ', validators[i].name);
15+
return false;
16+
}
17+
}
18+
19+
return true;
20+
}
21+
22+
// Create new validator instances
23+
function validator(name) {
24+
return {
25+
name: name,
26+
check: require('./validators/' + name)
27+
};
28+
}
29+
30+
31+
module.exports = validate;

lib/validators/func.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* Custom function validator
3+
*
4+
* {
5+
* func: function A function to validate. Must return true or false.
6+
* }
7+
*/
8+
9+
function isValid(data, model) {
10+
if(!model.func) {
11+
return true;
12+
}
13+
14+
return model.func(data);
15+
}
16+
17+
module.exports = isValid;

lib/validators/length.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/**
2+
* Length validator
3+
*
4+
* {
5+
* length: {
6+
* eq: Number, // Exact allowed value
7+
* max: Number, // Maximum allowed value
8+
* min: Number // Minimum allowed value
9+
* }
10+
* }
11+
*/
12+
13+
function isValid(data, model) {
14+
if(!model.length) {
15+
return true;
16+
}
17+
18+
// Data hasn't the exact eq lenght
19+
if(model.length.eq && data.length !== model.length.eq) {
20+
return false;
21+
}
22+
23+
// Data is higher than max
24+
if(model.length.max && data.length > model.length.max) {
25+
return false;
26+
}
27+
28+
// Data is lower than min
29+
if(model.length.min && data.length < model.length.min) {
30+
return false;
31+
}
32+
33+
return true;
34+
}
35+
36+
module.exports = isValid;

lib/validators/type.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Type validator
3+
*
4+
* {
5+
* type: String // Check if data has a JS type (uses typeof)
6+
* }
7+
*/
8+
9+
function isValid(data, model) {
10+
if(!model.type) {
11+
return false;
12+
}
13+
14+
if((typeof(data)).toUpperCase() === model.type.toUpperCase()) {
15+
return true;
16+
}
17+
18+
return false;
19+
}
20+
21+
module.exports = isValid;

lib/validators/value.js

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Value validator
3+
*
4+
* {
5+
* value: {
6+
* eq: String || Number, // Exact allowed value (equals)
7+
* max: Number, // Maximum allowed value
8+
* min: Number, // Minimum allowed value
9+
* contains: String || Number // The value contains
10+
* }
11+
* }
12+
*/
13+
14+
function isValid(data, model) {
15+
if(!model.value) {
16+
return true;
17+
}
18+
19+
// Data is different than equals
20+
if(model.value.eq) {
21+
if(typeof(data) === typeof(model.value.eq) && data !== model.value.eq) {
22+
// Same data type and different values
23+
return false;
24+
} else {
25+
// Different types: Try to convert one to other.
26+
var parsed = data;
27+
var type = typeof(model.value.eq);
28+
switch(type.toLowerCase()) {
29+
case 'string':
30+
parsed = String(data);
31+
break;
32+
case 'number':
33+
parsed = Number(data);
34+
break;
35+
case 'boolean':
36+
parsed = Boolean(data);
37+
break;
38+
}
39+
40+
if(data !== model.value.eq) {
41+
return false;
42+
}
43+
}
44+
}
45+
46+
// Data is higher than max
47+
if(model.value.max && Number(data) > Number(model.value.max)) {
48+
return false;
49+
}
50+
51+
// Data is lower than min
52+
if(model.value.min && Number(data) < Number(model.value.min)) {
53+
return false;
54+
}
55+
56+
// Data does not contain something
57+
if(model.value.contains && data.indexOf(model.value.contains) === -1) {
58+
return false;
59+
}
60+
61+
return true;
62+
}
63+
64+
module.exports = isValid;

0 commit comments

Comments
 (0)