-
Notifications
You must be signed in to change notification settings - Fork 22
/
7-build.js
117 lines (96 loc) · 2.67 KB
/
7-build.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
'use strict';
const accessors = {
string(proto, name, index) {
Object.defineProperty(proto.prototype, name, {
get() {
return this[index];
},
set(value) {
this[index] = value;
}
});
},
Date(proto, name, index) {
Object.defineProperty(proto.prototype, name, {
get() {
return new Date(this[index]);
},
set(value) {
this[index] = value instanceof Date ? value.toISOString() : value;
}
});
},
function(proto, name, index, fieldDef) {
Object.defineProperty(proto.prototype, name, { get: fieldDef });
}
};
// Assign prototype to records array or single record
// data - array of objects
// proto - dynamically built prototipe to be assigned
const assignPrototype = (data, proto) => {
if (Array.isArray(data)) {
data.forEach(item => item.__proto__ = proto.prototype);
} else {
Object.setPrototypeOf(data, proto.prototype);
}
};
// Build Prototype from Metadata
const buildPrototype = metadata => {
const protoClass = function ProtoClass() {};
let index = 0, fieldDef, buildGetter, fieldType;
for (const name in metadata) {
fieldDef = metadata[name];
fieldType = typeof fieldDef;
if (fieldType !== 'function') fieldType = fieldDef;
buildGetter = accessors[fieldType];
if (buildGetter) buildGetter(protoClass, name, index++, fieldDef);
}
return protoClass;
};
// Assign metadata to array elements
// data - array of objects
// metadata - data describes PrototypeClass structure
// Returns: built PrototypeClass
const assignMetadata = (data, metadata) => {
const proto = buildPrototype(metadata);
//Object.setPrototypeOf(data, proto);
assignPrototype(data, proto);
return proto;
};
// Usage
// Define Data Source
const data = [
['Marcus Aurelius', 'Rome', '212-04-26'],
['Victor Glushkov', 'Rostov on Don', '1923-08-24'],
['Ibn Arabi', 'Murcia', '1165-11-16'],
['Mao Zedong', 'Shaoshan', '1893-12-26'],
['Rene Descartes', 'La Haye en Touraine', '1596-03-31']
];
console.dir({ data });
// Define metadata to build prototype dynamically
const metadata = {
name: 'string',
city: 'string',
born: 'Date',
age() {
return (
new Date().getFullYear() -
new Date(this.born).getFullYear()
);
},
toString() {
return [this.name, this.city, this.born, this.age].join(', ');
}
};
// Define query using regular JavaScript syntax
const query = ({ name, age, city }) => (
name !== '' &&
age > 25 &&
city === 'Rome'
);
// Build prototype and assign to array elements
assignMetadata(data, metadata);
// Apply query to dataset
const res = data.filter(query);
console.dir({ res });
console.dir({ age: res[0].age });