dt-toolbox 5.0.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/Changelog.md +15 -10
  2. package/LICENSE +1 -1
  3. package/Migration.guide.md +63 -1
  4. package/README.md +996 -346
  5. package/README_v.2.x.x.md +0 -1
  6. package/README_v.4.x.x.md +532 -0
  7. package/README_v.6.x.x.md +1158 -0
  8. package/package.json +21 -24
  9. package/src/convertors/index.js +43 -34
  10. package/src/convertors/midflat.js +76 -132
  11. package/src/convertors/standard.js +61 -86
  12. package/src/convertors/tuples.js +171 -0
  13. package/src/flatData/connect.js +50 -0
  14. package/src/flatData/export.js +46 -0
  15. package/src/flatData/filters/list.js +11 -0
  16. package/src/flatData/filters/listObject.js +13 -0
  17. package/src/flatData/filters/object.js +12 -0
  18. package/src/flatData/filters/root.js +12 -0
  19. package/src/flatData/find.js +20 -0
  20. package/src/flatData/from.js +33 -0
  21. package/src/flatData/get.js +29 -0
  22. package/src/flatData/index.js +101 -0
  23. package/src/flatData/insert.js +24 -0
  24. package/src/flatData/like.js +24 -0
  25. package/src/flatData/look.js +56 -0
  26. package/src/flatData/push.js +19 -0
  27. package/src/flatData/save.js +17 -0
  28. package/src/flatData/set.js +26 -0
  29. package/src/flatData/setupFilter.js +21 -0
  30. package/src/flatData/use.js +16 -0
  31. package/src/flatObject/copy.js +19 -0
  32. package/src/flatObject/export.js +13 -0
  33. package/src/flatObject/index.js +55 -0
  34. package/src/flatObject/insert.js +38 -0
  35. package/src/flatObject/model.js +32 -0
  36. package/src/flatObject/query.js +24 -0
  37. package/src/flatObject/setupFilter.js +12 -0
  38. package/src/main.js +21 -689
  39. package/src/mainLib.js +114 -0
  40. package/src/compareMethod/change.js +0 -21
  41. package/src/compareMethod/different.js +0 -18
  42. package/src/compareMethod/identical.js +0 -21
  43. package/src/compareMethod/index.js +0 -13
  44. package/src/compareMethod/missing.js +0 -18
  45. package/src/compareMethod/same.js +0 -18
  46. package/src/convertors/breadcrumbs.js +0 -148
  47. package/src/help/extractSelection.js +0 -12
  48. package/src/help/filterObject.js +0 -25
  49. package/src/help/hasNumbers.js +0 -14
  50. package/src/help/index.js +0 -35
  51. package/src/help/isItPrimitive.js +0 -10
  52. package/src/help/objectsByLevel.js +0 -16
  53. package/src/help/reduceTuples.js +0 -29
  54. package/src/help/sanitizeFlatKeys.js +0 -30
  55. package/src/help/toBreadcrumbsKeys.js +0 -28
  56. package/src/help/tuplesToBreadcrumbs.js +0 -25
  57. package/src/help/updateSelection.js +0 -12
  58. package/src/help/zipObject.js +0 -24
  59. package/src/lib/assemble.js +0 -45
  60. package/src/lib/attach.js +0 -20
  61. package/src/lib/block.js +0 -33
  62. package/src/lib/combine.js +0 -38
  63. package/src/lib/deep.js +0 -23
  64. package/src/lib/find.js +0 -36
  65. package/src/lib/folder.js +0 -42
  66. package/src/lib/index.js +0 -56
  67. package/src/lib/modify.js +0 -22
  68. package/src/lib/parent.js +0 -51
  69. package/src/lib/purify.js +0 -37
  70. package/src/lib/transform.js +0 -55
  71. package/src/modifiers/add.js +0 -18
  72. package/src/modifiers/append.js +0 -18
  73. package/src/modifiers/combineShallow.js +0 -119
  74. package/src/modifiers/flatten.js +0 -38
  75. package/src/modifiers/index.js +0 -34
  76. package/src/modifiers/insert.js +0 -21
  77. package/src/modifiers/keyPrefix.js +0 -27
  78. package/src/modifiers/mix.js +0 -25
  79. package/src/modifiers/overwrite.js +0 -18
  80. package/src/modifiers/prepend.js +0 -19
  81. package/src/modifiers/reverse.js +0 -23
  82. package/src/modifiers/update.js +0 -18
  83. package/src/simple.js +0 -49
package/README.md CHANGED
@@ -1,24 +1,52 @@
1
- # DT Toolbox
2
- *Note: Document is valid for v.5.x.x, v.4.x.x and v.3.x.x*
1
+ # DT Toolbox v.7.x.x
3
2
 
4
- - [Documentation for old v.2.x.x is here](https://github.com/PeterNaydenov/dt-toolbox/blob/master/README_v.2.x.x.md)
3
+ ![version](https://img.shields.io/github/package-json/v/peterNaydenov/dt-toolbox)
4
+ ![license](https://img.shields.io/github/license/peterNaydenov/dt-toolbox)
5
5
 
6
- Execute operations over deep object structures without worries. Compare, modify, reshape or extract data. Immutability is taken as consideration by this library.
6
+ - [Documentatation for old v.6.x.x is here](htts://github.com/PeterNaydenov/dt-toolbox/blob/master/README_v.6.x.x.md)
7
7
 
8
- What you can do:
9
- - Library knows some data-types and supports conversion among them;
10
- - Modify objects: add/update/overwrite/insert/combine/append/prepend;
11
- - Compare objects: identical/change/same/different/missing;
12
- - Accumulative data selections: find/parent/folder;
13
- - Accumulative filter selection: limit/keep/remove/deep;
14
- - Extract and manipulate data chunks;
15
8
 
16
9
 
17
- ## Installation
10
+ ## Breaking changes
11
+ * In version 7 look functions have 2 new arguments: Function `finish` and `next`;
12
+ * Instead of returning a string 'next'(in version 6) to stop iteration on current dt-line, now you have to `return next()`;
13
+ * Function `finish` is a new option. Call `return finish()` to stop iteration on all dt-lines;
14
+ * Method `insert` was renamed to `insertSegment` to be clear that data is not mixed. Segments are separated peaces of data;
15
+
16
+
17
+
18
+ ## Other changes
19
+ * Method `listSegments` was added to show list of all segments in dt-object;
20
+ * Method `insertSegment` expect the incoming data as dt-object, but if is not - will assume it as a standard javascript object and will convert it to dt-object automatically;
21
+
22
+
23
+ ## Description
24
+
25
+ DT-Toolbox is created to simplify the work with deep nested javascript objects. The library was created as an immutable data-storage(dt-object), internally based on data-model called `DT-model`.
26
+
27
+ ## What is DT-model?
28
+ It's an internal 'dt-object' data description. Data is an array of lines where each line has 4 components:
29
+ ```js
30
+ [ // dt-model
31
+ [ name, flatData, breadcrumbs, edges ] // dt-line
32
+ , [ name, flatData, breadcrumbs, edges ] // dt-line
33
+ // ...
34
+ ]
35
+ // Where ->
36
+ // name: string. Name of the dt-line;
37
+ // flatData: object or array of primitive types;
38
+ // breadcrumbs: string. Bredcrumbs description of the current dt-line;
39
+ // edges: string[]. List of breadcrumbs of the related dt-lines;
40
+ ```
41
+
42
+ This data-description is easy to read, saved, or transfered.
18
43
 
44
+
45
+ ## Installation
19
46
  Install for node.js projects by writing in your terminal:
47
+
20
48
  ```
21
- npm install dt-toolbox --save
49
+ npm install dt-toolbox
22
50
  ```
23
51
 
24
52
  Once it has been installed, it can be used by writing this line of JavaScript:
@@ -28,458 +56,910 @@ import dtbox from 'dt-toolbox'
28
56
 
29
57
 
30
58
 
31
- ## APIs Reference
59
+ ## How it works?
60
+
61
+ Use Dt-toolbox methods(init and load) to create a `dt-object`.
62
+
63
+ DT-object:
64
+ - Provides multiple insertion of data segments. Data from each insertion stays differentiated;
65
+ - Has prebuilded filters for fast search of data;
66
+ - Can create and register a customized filters for fast search of data;
67
+ - Can apply `query functions` to find, extract and reshape the data;
68
+ - Can apply `model function` to reshape the final result;
69
+ - Can executes 'query' and 'model' function over all available data in the storage (All data segments);
70
+ - Execution of query/model functions will not change anything inside the host dt-object;
71
+
72
+ The **dt-object** contains internally a `dt-storage` object, that is available during call of the 'query' or 'model' functions. Dt-storage have couple of methods for searching data as well can create a new **DT-model** structures and fill them with data.
32
73
 
33
- Dtbox API methods with a short description:
74
+ Query functions are returning a **new instance of dt-object** with the result, created by dt-storage. Remember - **data inside dt-object never get modified**.
75
+
76
+ **Filters** can significantly improve the speed of searching information inside dt-objects by creating a shorter scan-list according some specific preferences. Library is coming with `list of predefined filters`:
77
+ ```js
78
+ 'list' : 'Scan only dt-lines where flatData is an array'
79
+ , 'listObject' : 'Scan objects that are members of array'
80
+ , 'object' : 'Scan just dt-lines where flatData is an object'
81
+ , 'root' : 'Scan only root dt-lines of each data segment'
82
+ ```
83
+ Filters are very simple functions to build. Here is one example of how we can create filter for finding object with specific key and value in it.
34
84
  ```js
35
- const API = {
36
- // DT I/O Operations
37
- init : 'Convert any object to flat data-type'
38
- , load : 'Load a flat data-type'
39
- , loadFast : 'Important! Method is depricated. Use load instead'
85
+ function findBlueEyesFn ({ // We have named arguments
86
+ name // Name of dt-line
87
+ , flatData // The data. Flat object or array
88
+ , breadcrumbs // Location description
89
+ , edges // List of breadcrumbs related to this dt-line
90
+ }) {
91
+ if ( flatData.eyes === 'blue' ) return true // confirm that dt-line should be in that filter list
92
+ return false // ignore this dt-line
93
+ }
94
+
95
+ // Register a filter to some dt-object:
96
+ dt.setupFilter (
97
+ 'blueEyes' // filter name
98
+ , findBlueEyesFn // provide a filter function
99
+ )
100
+ // Filter function will be executed on each dt-line to create a filter scan-list
101
+
102
+ // Using the filter during execution of query/model functions:
103
+ dt.query ( store => {
104
+ store
105
+ .use ( 'blueEyes' ) // Set the name of the filter
106
+ .look ( ({}) => {
107
+ // ... will scan only dt-lines selected by filter
108
+ })
109
+ })
110
+ ```
40
111
 
41
- , preprocess : 'Apply custom modifier to initial data.
42
- , add : 'Add data and keep existing data'
43
- , update : 'Updates only existing data fields'
44
- , overwrite : 'Add new data to DT object. Overwrite existing fields'
45
- , insert : 'Insert data on specified key, when the key represents an array'
46
- , combine : 'Combine values for simular keys in arrays'
47
- , append : 'Combine values for duplicated keys. main + update'
48
- , prepend : 'Combine values for duplicated keys. update + main'
49
- , log : 'Executes callback with errors list as argument'
50
- , empty : 'Empty object with export methods'
112
+ Take a look on the library APIs and see the '**Examples**' section bellow.
51
113
 
52
- // Provide Results
53
- , replace : 'Get this._selection.result as a main data'
54
- , attach : 'Attach this._selection.result to the main data. Set point of connection'
55
- , spread : 'Returns result of selection in a calback function'
56
- , spreadAll : 'Select all and returns it with one command in a callback function'
57
- , export : 'Returns result of selection'
58
- , exportAll : 'Select all and returns it with one command'
114
+ ### dt-toolbox API Fast Reference
59
115
 
60
- // Compare Operations
61
- , identical : 'Value compare. Reduce data to identical key/value pairs'
62
- , change : 'Value compare. Reduce to key/value pairs with different values'
63
- , same : 'Key compare. Returns key/value pairs where keys are the same'
64
- , different : 'Key compare. Returns key/value pairs where key does not exist'
65
- , missing : 'Key compare. Returns key/value pairs that are missing'
66
-
67
- // Selectors
68
- , select : 'Initialize a new selection'
69
- , parent : 'Selector. Apply conditions starting from parent level'
70
- , find : 'Selector. Fullfil select with list of arguments that contain specific string'
71
- , all : "Selector. Same as find ('root')"
72
- , folder : "Selector. Fullfil selection with 'midFlat' object props"
73
- , space : "Selector. Same as 'folder'"
74
- , deepObject : "Selector. Fullfil '_select' with deepest object elements"
75
- , deepArray : "Selector. Fullfil '_select' with deepest array elements"
76
- , invert : 'Selector. Invert existing selection'
77
- , assemble : "Converts selection into 'array of objects' or 'single flat object'"
78
- , purify : 'Removes all empty structures ( no props ) from the selection'
116
+ ```js
117
+ init : 'Create a new dt-object from data that is not a DT-model and needs a convertion'
118
+ , load : 'Create a new dt-object from data that is a DT-model'
119
+ , flat : 'Convert a data to DT-model without creation of dt-object'
120
+ , convert : 'Direct convertion from model to model without creation of dt-object'
121
+ , getWalk : 'Returns a instance of "walk" library'
122
+ ```
79
123
 
80
- // Filters
81
- , limit : 'Filter. Reduces amount of records in the selection'
82
- , keep : 'Filter. Keeps records in selection if check function returns true'
83
- , remove : 'Filter. Removes records from selection if check function returns true'
84
- , deep : "Filter. Arguments ( num, direction - optional). Num mean level of deep. Deep '0' mean root members"
124
+ ### dt-object API Fast Reference
85
125
 
86
- // Modifiers
87
- , withData : 'Generate "this._select.result" from the official data. Modifier will work with this data'
88
- , withSelection : 'Generate "this._select.result" content. Modifier will work with this data'
89
- , flatten : 'Mix existing objects in a single object'
90
- , mix : 'Mix objects in order. Start with a host and provide guests list []'
91
- , keyPrefix : 'Modify key as object name+key. Separator-symbol default: emptySpace. It can be modified'
92
- , reverse : 'Change place of keys and values'
93
- }; // API
126
+ ```js
127
+ insertSegment : 'Inserts a new data-segment in the dt-object. Insertion should be provided as a dt-object.'
128
+ , 'export' : 'Returns the DT-model from dt-object - part or full'
129
+ , copy : 'Creates a copy of original provided data'
130
+ , query : 'Executes a "query" function on the dt-object. Returns a new dt-object with the result'
131
+ , model : 'Executes a "model" function on the dt-object. Returns a data model'
132
+ , setupFilter : 'Evaluate data according "filter" function and create a shorter scan list that can be used by "dt-storage" during execution of query and model functions'
133
+ , index : 'Provides a copy of specified dt-line by breadcrumbs'
134
+ , listSegments : 'Returns a list of all segments in dt-object'
94
135
  ```
95
136
 
137
+ ### dt-storage API Fast Reference
96
138
 
139
+ Object `dt-storage` is available as argument to '**query**' and '**model**' functions. Methods of
140
+ 'dt-storage' can scan DT-model for data and build a new DT-model structure and fields.
97
141
 
142
+ *Important*: Result of building a DT-model returns as a separate dt-object and will not modify anything inside actual dt-object.
98
143
 
144
+ ```js
145
+ // Scan methods
146
+ , from : 'Scan deeper from specified dt-line by location(breadcrumbs)'
147
+ , use : 'Use filter name to execute `look` on shorter list of dt-lines.'
148
+ , get : 'Take a single dt-line with specific breadcrumbs'
149
+ , find : 'String search for exact object name'
150
+ , like : 'String search in dt-line name'
151
+ , look : 'Executes on each object property in the selection list'
152
+
153
+ // DT-model structure and fields creation:
154
+ set : 'Define new dt-line record'
155
+ , connect : 'Creates a list of connections between two already existing dt-lines'
156
+ , save : 'Save a property to flatData object in existing dt-line'
157
+ , push : 'Save a value to flatData array of existing dt-line'
99
158
 
100
- # How it works?
159
+ ```
101
160
 
102
- 1. First: Insert data in dt-toolbox. Use `load` for `flat` data-type or `init` for other data-types. Mix with other objects by using 'add/update/overwrite/combine' if you need. Use 'preprocess' to change data-type before assimilate it.
103
161
 
104
- 2. Select! Without selection, dt-toolbox will return an empty object. Selection respresents the information that should be extracted from the data. Result of selectors is accumulative. Filters will be applied to already selected data.
105
162
 
106
- 3. Spread/Export the result. Create new data structure according selection and provide it in required data-type.
163
+ ## DT Toolbox API
107
164
 
108
- DT Toolbox supports chaining syntax and is that simple. Let's see some examples...
165
+ ### dtbox.init ()
166
+ Create a new dt-object from data that is not a DT-model and needs a convertion. Please take a look on section `Init/Export Data-Models` for more details.
109
167
 
168
+ ```js
169
+ const data = { // Standard JS object
170
+ name: 'Peter'
171
+ , familyMembers : [ 'Veselina', 'Iskra', 'Maria', 'Vasil', 'Vladimir', 'Petya' ]
172
+ , shoes : {
173
+ winter : [ 'Keen', 'Head']
174
+ , summer : [ 'Lotto', 'Asics' ]
175
+ }
176
+ };
177
+
178
+ const midData = { // Midflat model object
179
+ 'root' : { name: 'Peter' }
180
+ , 'familyMembers' : ['Veselina', 'Iskra', 'Maria', 'Vasil', 'Vladimir', 'Petya' ]
181
+ , 'shoes/winter' : [ 'Keen', 'Head' ]
182
+ , 'shoes/summer' : [ 'Lotto', 'Asics' ]
183
+ }
184
+
185
+ const dtS = dtbox.init ( data ) // Creates dt-object from 'standard'(std) data-model
186
+ // it's equal to this: const dtS = dtbox.init ( data, { model:'std' })
187
+ const dtMid = dtbox.init ( midData, { model : 'midFlat' }) // Creates a dt-object from midFlat data.
188
+ ```
110
189
 
111
190
 
112
191
 
192
+ ### dtbox.load ()
193
+ Create a new dt-object from data that is a DT-model.
113
194
 
195
+ ```js
196
+ const dtData = [
197
+ [
198
+ 'root',
199
+ { city: 'Varna', desc: 'Big city on the Black-sea seaside' },
200
+ 'root',
201
+ [ 'root/location', 'root/extra' ]
202
+ ],
203
+ [
204
+ 'location',
205
+ { continent: 'Europe', country: 'Bulgaria' },
206
+ 'root/location',
207
+ []
208
+ ],
209
+ [
210
+ 'extra',
211
+ { port: 'Yes', airport: 'Yes' },
212
+ 'root/extra',
213
+ [ 'root/extra/nearTo' ]
214
+ ],
215
+ [
216
+ 'nearTo',
217
+ [ 'Burgas', 'Shumen', 'Dobrich' ],
218
+ 'root/extra/nearTo',
219
+ []
220
+ ]
221
+ ];
114
222
 
223
+ const dtStore = dtbox.load ( dtData ); // Load DT-model data to dt-object
224
+ ```
115
225
 
116
226
 
117
227
 
228
+ ### dtbox.flat ()
229
+ Convert a data to DT-model without creation of dt-object.
118
230
 
119
- ## Examples
231
+ ```js
232
+ const a = {
233
+ city : 'Varna'
234
+ , desc: 'Big city on the Black-sea seaside'
235
+ , location : {
236
+ continent: 'Europe'
237
+ , country : 'Bulgaria'
238
+
239
+ }
240
+ , extra : {
241
+ port : 'Yes'
242
+ , airport : 'Yes'
243
+ , 'nearTo' : [ 'Burgas', 'Shumen', 'Dobrich' ]
244
+ }
245
+ };
246
+
247
+ const inFlatModel = dtbox.flat ( a ) // Default data-model is set to 'standard'(std)
248
+ // it's equal to: const inFlatModel = dtbox.flat ( a, {model: 'std'})
249
+ /**
250
+ * inFlatModel = [
251
+ [
252
+ 'root',
253
+ { city: 'Varna', desc: 'Big city on the Black-sea seaside' },
254
+ 'root',
255
+ [ 'root/location', 'root/extra' ]
256
+ ],
257
+ [
258
+ 'location',
259
+ { continent: 'Europe', country: 'Bulgaria' },
260
+ 'root/location',
261
+ []
262
+ ],
263
+ [
264
+ 'extra',
265
+ { port: 'Yes', airport: 'Yes' },
266
+ 'root/extra',
267
+ [ 'root/extra/nearTo' ]
268
+ ],
269
+ [
270
+ 'nearTo',
271
+ [ 'Burgas', 'Shumen', 'Dobrich' ],
272
+ 'root/extra/nearTo',
273
+ []
274
+ ]
275
+ ]
276
+ */
277
+
278
+ ```
120
279
 
121
- Here are some use cases, but if you're interested, test-cases are on your disposal.
122
- ### Basics
123
- Let's have a standard JS object:
280
+
281
+
282
+ ### dtbox.convert ()
283
+ Direct convertion from model to model without creation of dt-object.
124
284
 
125
285
  ```js
126
- let st = {
127
- name : {
128
- firstName : 'Peter'
129
- , surname : 'Naydenov'
130
- }
131
- , friends : [ 'Tisho', 'Dibo', 'Ivo', 'Vasil' ]
132
- }
133
286
 
287
+ let result = dtbox.convert ( a, {
288
+ model : 'std' // Model: Source data-model
289
+ , as : 'breadcrumbs' // as: Convert data to this data-model
290
+ })
291
+
292
+ /**
293
+ result = {
294
+ 'city': 'Varna'
295
+ , 'desc': 'Big city on the Black-sea seaside'
296
+ , 'location/continent': 'Europe'
297
+ , 'location/country': 'Bulgaria'
298
+ , 'extra/port': 'Yes'
299
+ , 'extra/airport': 'Yes'
300
+ , 'extra/nearTo/0': 'Burgas'
301
+ , 'extra/nearTo/1': 'Shumen'
302
+ , 'extra/nearTo/2': 'Dobrich'
303
+ }
304
+ */
134
305
  ```
135
- Put the **st** data into dt-toolbox:
306
+
307
+
308
+
309
+ ### dtbox.getWalk ()
310
+ Dt-Toolbox is using "walk" library. If you need to use it directly - get the version used by Dt-Toolbox.
136
311
 
137
312
  ```js
138
- let dt = dtbox.init ( standard )
313
+ const walk = dtbox.getWalk ();
314
+
139
315
  ```
140
316
 
141
- Internal representation of data is based on `flat` data-type. Type `flat` has two elements: value and structure.
142
- **Value** represents primitive values and their location. **Structure** represents existing flat objects and their relations.
143
- Our standard object inside the library will look like:
317
+
318
+
319
+
320
+
321
+ ## DT-object API
322
+
323
+
324
+ ### dt.insertSegment ()
325
+ Extend the dt-object with a new data segment. Insertion should be provided as dt-object.
144
326
 
145
327
  ```js
146
- dt.structure = [
147
- // type i object descriptors [i, name]
148
- [ 'object', 0, [1, name], [2, friends] ] // Root object and relation with other objects
149
- , [ 'object', 1 ] // st.name object. Object has only primitive values.
150
- , [ 'array' , 2 ] // st.friends array. Array has only primitive values.
328
+ const a = [ // it's a 'file' data-model
329
+ 'name/Peter'
330
+ , 'familyMembers/Veselina'
331
+ , 'familyMembers/Iskra'
332
+ , 'familyMembers/Maria'
333
+ , 'familyMembers/Vasil'
334
+ , 'familyMembers/Vladimir'
335
+ , 'familyMembers/Petya'
336
+ , 'shoes/winter/Keen'
337
+ , 'shoes/winter/Head'
338
+ , 'shoes/summer/Lotto'
339
+ , 'shoes/summer/Asics'
340
+ ];
341
+ const b = { shoes: [ 'Puma', 'UA' ]}
342
+ const dt = dtbox.init ( a, { model : 'file' }) // create a dt-object
343
+ dt.insertSegment (
344
+ 'extra' // object name
345
+ , dtbox.init(b) // the extra object
346
+ ) // insert to 'dt' storage data segment named 'extra' with data from 'b' object
347
+
348
+ /**
349
+ dt internal interpretation:
350
+ [
351
+ [
352
+ 'root' // -> dt-line name
353
+ , {name:'Peter'} // -> flatData
354
+ , 'root' // -> location. For top element of each data segment breadcrumbs === name
355
+ , [ 'root/familyMembers', 'root/shoes' ] // -> edges
356
+ ]
357
+ , [
358
+ 'familyMembers' // -> dt-line name
359
+ , [ 'Veselina', 'Iskra', 'Maria', 'Vasil', 'Vladimir', 'Petya' ] // -> flatData
360
+ , 'root/familyMembers' // -> location
361
+ , [] // -> edges
362
+ ]
363
+ , [
364
+ 'shoes' // -> dt-line name
365
+ , {} // -> flatData
366
+ , 'root/shoes' // -> location
367
+ , [ 'root/shoes/winter', 'root/shoes/summer' ] // -> edges
368
+ ]
369
+ , [
370
+ 'winter' // -> dt-line name
371
+ , [ 'Keen', 'Head' ] // -> flatData
372
+ , 'root/shoes/winter' // -> location
373
+ , [] // -> edges
374
+ ]
375
+ , [
376
+ 'summer' // -> dt-line name
377
+ , [ 'Lotto', 'Asics' ] // -> flatData
378
+ , 'root/shoes/summer' // -> location
379
+ , [] // -> edges
380
+ ]
381
+ // ---> Here are the elements that are coming from 'insertSegment'
382
+ , [
383
+ 'extra' // -> dt-line name. Object name of insert will become root element for data segment.
384
+ , {} // -> flatData
385
+ ,'extra' // -> location. For top element of each data segment breadcrumbs === name
386
+ , [ 'extra/shoes' ] // -> edges
151
387
  ]
388
+ , [
389
+ 'shoes' // -> dt-line name
390
+ , [ 'Puma', 'UA'] // -> flatData
391
+ , 'extra/shoes' // -> location
392
+ , [] // -> edges
393
+ ]
394
+ ]
152
395
 
153
- dt.value = { // Represents a primitive props and their location
154
- 'root/1/firstName' : 'Peter'
155
- , 'root/1/surname' : 'Naydenov'
156
- , 'root/2/0' : 'Tisho'
157
- , 'root/2/1' : 'Dibo'
158
- , 'root/2/2' : 'Ivo'
159
- , 'root/2/3' : 'Vasil'
160
- }
161
- }
396
+ */
162
397
  ```
163
398
 
164
- ::: warning
165
- Internal representation is '*LIKE*' flat data-type but not the data-type itself. Type `flat` is array with two elements: structure and value `[structure, value]`. Internal representation has these two elements but they are like props. `dt = { structure, value }`.
166
- :::
167
399
 
168
400
 
401
+ ### dt.export ()
402
+ Returns DT-model from dt-object.
169
403
 
170
- Extract a flat information:
171
404
  ```js
172
- dt.spreadAll ( 'flat', res => {
173
- // Data-type 'Flat': An array with 2 entries: [structure, value]
174
- })
175
- // other way to receive same result:
176
- let myFlat = dt.exportAll ( 'flat' )
405
+ const all = dt.export () // will return all data from the storage
406
+ const root = dt.export ( 'root' ) // will return only initial data segment
407
+ const extra = dt.export ( 'extra' ) // will return only 'extra' data segment
408
+ /**
409
+ extra = [
410
+ , [
411
+ 'root' // -> dt-line name was changed to 'root'. Name 'extra' has meaning just inside dt-object
412
+ , {} // -> flatData
413
+ ,'root' // -> location. For top element of each data segment breadcrumbs === name
414
+ , [ 'root/shoes' ] // -> edges
415
+ ]
416
+ , [
417
+ 'shoes' // -> dt-line name
418
+ , [ 'Puma', 'UA'] // -> flatData
419
+ , 'root/shoes' // -> location
420
+ , [] // -> edges
421
+ ]
422
+ ]
423
+ */
424
+
177
425
  ```
178
426
 
179
427
 
428
+ ### dt.copy ()
429
+ During the initialization process `dt-object` will save a deep copy of original data inside and can provide a deep copy in any time.
430
+ Function `copy` can't provide copy of all data segments together because they are not related to each other. By default, when there is no name as argument, function will return the copy of 'root' object.
431
+ ```js
432
+ const
433
+ b = { shoes: [ 'Puma', 'UA' ]}
434
+ , c = { vitamins : [ 'a', 'b', 'c' ]}
435
+ , dt = dtbox.init ( b )
436
+ ;
437
+ dt.insertSegment ( 'extra', c )
438
+ const deepCopy = dt.copy ()
439
+ // it equal to: const deepCopy = dt.copy ('root')
440
+ const onlyExtra = dt.copy ( 'extra' )
441
+ // onlyExtra = { vitamins : [ 'a', 'b', 'c' ]}
442
+ ```
180
443
 
181
- Let's play with DT Toolbox:
182
444
 
445
+
446
+ ### dt.query ()
447
+ Executes a "query" function on the dt-object. If there is something new, will return it. If there are no changes, it will return itself. For more details take a look on `store API` and especially **store.set(), store.save(), store.push(), store.connect()**.
183
448
  ```js
184
- let
185
- dtResult
186
- , stResult
187
- , friendList
188
- ;
449
+ function queryFn ( store, a, b ) { // optional arguments will come directly after 'store' api
450
+ // ... body of queryFn
451
+ }
452
+ const dtOther = dt.query ( queryFn, a, b ) // queryFn is required arguments. All other arguments are optional
453
+ ```
454
+
455
+
456
+ ### dt.model ()
457
+ Executes a "model" function on the dt-object. Returns a data-model. Default choice is DT-model object. Change the response representation by returning an object as in example below:
458
+ ```js
459
+ function modelFn ( store, a,v,g ) { // optional arguments will come directly after 'store' api
460
+ // ... body of modelFn
461
+ // to convert result in some of predefined and supported models, function should return an object
462
+ return {
463
+ as : 'std' // property 'as' will execute final conversion. Model name should be from supported list of the library.
464
+ }
465
+ }
466
+
467
+ const result = dt.model ( modelFn, a,v,g ) // modelFn is the only required argument. All other arguments are optional.
189
468
 
190
- dtbox
191
- .init(st) // Init data. Converts ST to DT
192
- .select() // Starting new selection
193
- .all() // Select all data
194
- .spread ( 'flat', dt => dtResult = dt ) // Returns as `flat` data-type
195
- .spread ( 'std', dt => stResult = dt ) // Convert back to original 'st' object
196
- .select () // Start new selection. Will remove previous selection.
197
- .find ( 'friends' ) // select keys that contain 'friends'
198
- .spread ( 'std', dt => friendList = dt ) //= { friends :[ 'Tisho', 'Dibo', 'Ivo', 'Vasil' ] }
199
- .assemble ()
200
- .spread ( 'std' => friendList = dt ) // = [ 'Tisho', 'Dibo', 'Ivo', 'Vasil' ]
201
- // 'assemble' removes all duplicated elements in the keys and simplifies the result.
202
-
203
469
  ```
204
470
 
205
- ### Convert ST to DT objects
471
+ ### dt.setupFilter ()
472
+ Evaluate data according "filter" function and create a shorter scan list that can be used by `dt-storage API` during the execution of query or model functions. For more details about filters look at function `store.use()` function.
206
473
 
207
474
  ```js
208
- let result;
209
- dtbox
210
- .init(st)
211
- .spreadAll ( 'flat', dt => result = dt );
475
+ function blueFn ({
476
+ name // Name of dt-line
477
+ , flatData // The flat data
478
+ , breadcrumbs // Location description
479
+ , edges // List of breadcrumbs related to this dt-line
480
+ }) {
481
+ if ( flatData.hasOwnProperty('eyes') && flatData.eyes === 'blue' ) return true // confirm that dt-line should be in that filter list
482
+ return false // ignore this dt-line
483
+ // dt-lines that are
484
+ }
485
+
486
+ dt.setupFilter (
487
+ 'blue' // Name of the filter
488
+ , blueFn // Provide a filter function
489
+ )
212
490
  ```
213
491
 
214
- ### Mixing objects - Add/Update/Overwrite
215
492
 
216
- Add and update will consider existing data:
217
- - 'Add' method will be applied only for non-existing properties;
218
- - 'Update' method will works only on existing properties;
493
+ ### dt.index ()
494
+ Provides a copy of specified by breadcrumbs DT-line.
495
+ ```js
496
+ const br = 'root/friends'
497
+ const data = {
498
+ name: 'Peter'
499
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
500
+ , personal : {
501
+ age : 49
502
+ , eyes : 'blue'
503
+ , sizes : [ 10, 44, 'm', 'mid' ]
504
+ , hobbies : {
505
+ music : [ 'punk', 'ska', 'metal', 'guitar' ]
506
+ , sport : [ 'fencing', 'skating', 'ski' ]
507
+ }
508
+ }
509
+ }
510
+ const [ name, flatData, breadcrumbs, edges ] = dt.index ( br )
511
+ // name = friends
512
+ // flatData = [ 'Ivan', 'Dobroslav', 'Stefan' ]
513
+ // breadcrumbs === br
514
+ // edges === []
515
+ ```
516
+
517
+ ### dt.listSegments ()
219
518
 
220
- Overwrite will 'add' and 'update'.
519
+ Returns a list of all data segment names. Result is always an array with at least one element - 'root'.
221
520
 
222
521
  ```js
522
+ dt.listSegments ()
523
+ // [ 'root', 'extra' ]
524
+ ```
223
525
 
224
- let user = {
225
- name : 'Peter'
226
- , age : 42
227
- }
228
526
 
229
- dtbox
230
- .init ( user )
231
- .add ({
232
- age : 25 // 'add' will ignore this. Age is already defined.
233
- , gender : 'male' // Will add this.
234
- }, { type: 'std'})
235
- .update ({
236
- age : 50 // Will update
237
- eyes : 'blue' // Will ignore this.
238
- }, { type: 'std'})
239
- .overwrite ({
240
- age : 43 // Will update
241
- , hobby : 'skating' // Will add
242
- }, { type: 'std'})
243
527
 
244
- // The object (dtbox.value) will look like:
245
- /*
246
- {
247
- 'root/0/name' : 'Peter'
248
- , 'root/0/age' : 43
249
- , 'root/0/gender' : 'male'
250
- , 'root/0/hobby' : 'skating'
251
- }
252
528
 
253
- /*
254
529
 
530
+
531
+
532
+ ## DT-store API
533
+
534
+ As we already mentioned, store is available in query/model functions and coming as the first argument.
535
+
536
+ ### store.look ()
537
+ Function that will be executed on each object key/value from the selection list.
538
+ If selection is not explicitly mentioned, executes function on each dt-line data segments.
539
+
540
+ ```js
541
+ const data = {
542
+ name: 'Peter'
543
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
544
+ , personal : {
545
+ age : 49
546
+ , eyes : 'blue'
547
+ , sizes : [ 10, 44, 'm', 'mid' ]
548
+ , hobbies : {
549
+ music : [ 'punk', 'ska', 'metal', 'guitar' ]
550
+ , sport : [ 'fencing', 'skating', 'ski' ]
551
+ }
552
+ }
553
+ };
554
+ const dt = dtbox.init ( data );
555
+
556
+ const result = dt.query ( store => {
557
+ // Direct call of look on store will be executed on each dt-line
558
+ store.look ( ({ // Named arguments. All available argument-names are listed here:
559
+ value
560
+ , key
561
+ , name // dt-line name;
562
+ , flatData // full flatData for specified dt-line;
563
+ , breadcrumbs // breadcrumbs for dt-line;
564
+ , links // List of tuples [[parent, child],...]. Parent and child are the dt-line names;
565
+ , empty // Will present only if object has no properties. Empty flatData for dt-line.
566
+ , next // Function that can be returned to move to next dt-line
567
+ , finish // Function that can be returned to stop execution of look function
568
+ }) => {
569
+ //... body of look function
570
+ // Move fast to next dt-line by returning a string 'next'
571
+ return next ()
572
+ // unconditional `return next()` will executes the 'look' function once per dt-line
573
+ })
574
+ })
575
+ ```
576
+
577
+ ### store.from ()
578
+ Scan deeper from specified dt-line by location(breadcrumbs).
579
+
580
+ ```js
581
+ const data = {
582
+ name: 'Peter'
583
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
584
+ , personal : {
585
+ age : 49
586
+ , eyes : 'blue'
587
+ , sizes : [ 10, 44, 'm', 'mid' ]
588
+ , hobbies : {
589
+ music : [ 'punk', 'ska', 'metal', 'guitar' ]
590
+ , sport : [ 'fencing', 'skating', 'ski' ]
591
+ }
592
+ }
593
+ };
594
+ const
595
+ dt = dtbox.init ( data )
596
+ , res = dt.query ( store => {
597
+ store
598
+ .from ( 'root/personal/hobbies' )
599
+ .look ( ({name, next }) => {
600
+ console.log ( name )
601
+ // -> hobbies, music, sport
602
+ return next () // because we want to iterate once on each dt-line
603
+ })
604
+ });
255
605
  ```
256
606
 
257
607
 
258
- ### Parent
608
+ ### store.use ()
609
+ Use filter to execute `look` on shorter list of dt-lines. Use the predefined or your own filters.
610
+ List of predefined filters:
611
+ - 'list' : Scan only dt-lines where flatData is an array;
612
+ - 'listObject' : Scan objects that are members of array;
613
+ - 'object' : Scan just dt-lines where flatData is an object;
614
+ - 'root' : Scan only root dt-lines of each data segment;
615
+
616
+ If filter do not exist, look function will be executed on each dt-line.
259
617
 
260
618
  ```js
619
+ const data = {
620
+ name: 'Peter'
621
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
622
+ , personal : {
623
+ age : 49
624
+ , eyes : 'blue'
625
+ , sizes : [ 10, 44, 'm', 'mid' ]
626
+ , hobbies : {
627
+ music : [ 'punk', 'ska', 'metal', 'guitar' ]
628
+ , sport : [ 'fencing', 'skating', 'ski' ]
629
+ }
630
+ }
631
+ };
632
+ const
633
+ dt = dtbox.init ( data )
634
+ , res = dt.query ( store => {
635
+ store
636
+ .use ( 'object' ) // predefined filter 'object'
637
+ .look ( ({name, next }) => {
638
+ console.log ( name )
639
+ // -> root, personal, hobbies
640
+ return next () // because we want to iterate once on each dt-line
641
+ })
642
+ });
643
+ ```
261
644
 
262
- let result;
263
- let data = {
264
- 'school' : [
265
- { name: 'Ivan', age: 14 }
266
- , { name: 'Georgy', age: 15 }
267
- , { name: 'Adi', age: 11 }
268
- , { name: 'Kati', age: 11 }
269
- ]
270
- , 'sports' : [
271
- { name: 'Iva', age: 28 }
272
- , { name: 'Stoyan', age: 36 }
273
- ]
274
- , 'work' : [
275
- { name: 'Hristo', age: 38 }
276
- , { name: 'Lachezar', age: 33 }
277
- , { name: 'Veselina', age: 35 }
278
-
279
- ]
280
- , 'recent' : {
281
- 'classmates' : [
282
- { name: 'Anton', age: 42 }
283
- , { name: 'Miroslava', age: 42 }
284
- ]
285
- , 'social' : [
286
- { name: 'Iliana', age: 61 }
287
- , { name: 'Tzvetan', age: 19 }
288
- ]
289
- }
290
- }
291
645
 
292
- // Let's create list of all contacts uder 40 years old:
293
-
294
- dtbox
295
- .init ( data )
296
- .select ()
297
- .parent ( 'name', person => person.age < 40 )
298
- .assemble ()
299
- .spread ( 'std' , dt => result = dt )
300
-
301
- /*
302
- result will look like this:
303
-
304
- [
305
- { name: 'Tzvetan', age: 19 },
306
- { name: 'Ivan', age: 14 },
307
- { name: 'Iva', age: 28 },
308
- { name: 'Hristo', age: 38 },
309
- { name: 'Georgy', age: 15 },
310
- { name: 'Stoyan', age: 36 },
311
- { name: 'Lachezar', age: 33 },
312
- { name: 'Adi', age: 11 },
313
- { name: 'Veselina', age: 35 },
314
- { name: 'Kati', age: 11 }
315
- ]
316
646
 
317
- */
647
+
648
+
649
+ ### store.get ()
650
+ Take a single dt-line with specific breadcrumbs.
651
+
652
+ ```js
653
+ const data = {
654
+ name: 'Peter'
655
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
656
+ , personal : {
657
+ age : 49
658
+ , eyes : 'blue'
659
+ , sizes : [ 10, 44, 'm', 'mid' ]
660
+ , hobbies : {
661
+ music : [ 'punk', 'ska', 'metal', 'guitar' ]
662
+ , sport : [ 'fencing', 'skating', 'ski' ]
663
+ }
664
+ }
665
+ };
666
+ const
667
+ dt = dtbox.init ( data )
668
+ , res = dt.query ( store => {
669
+ store
670
+ .get ( 'root/friends' )
671
+ .look ( ({ flatData, next }) => {
672
+ console.log ( flatData )
673
+ // -> [ 'Ivan', 'Dobroslav', 'Stefan' ]
674
+ return next () // because we want to iterate once on each dt-line
675
+ })
676
+ });
318
677
  ```
319
678
 
320
679
 
321
680
 
322
- ### Purify
681
+ ### store.find ()
682
+ String search for exact object name
683
+
684
+ ```js
685
+ const data = {
686
+ name: 'Peter'
687
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
688
+ , personal : {
689
+ age : 49
690
+ , eyes : 'blue'
691
+ , sizes : [ 10, 44, 'm', 'mid' ]
692
+ , hobbies : {
693
+ music : [ 'punk', 'ska', 'metal', 'guitar' ]
694
+ , sport : [ 'fencing', 'skating', 'ski' ]
695
+ }
696
+ }
697
+ };
698
+ const
699
+ dt = dtbox.init ( data )
700
+ , res = dt.query ( store => {
701
+ store
702
+ .find ( 'music' )
703
+ .look ( ({flatData, next }) => {
704
+ console.log ( flatData )
705
+ // -> [ 'punk', 'ska', 'metal', 'guitar' ]
706
+ return next () // because we want to iterate once on each dt-line
707
+ })
708
+ });
709
+ ```
323
710
 
324
- Cleaning empty structures till version 3 of the library was without alternative. Keep empty structures was recognized as a need and it's now a default behaviour. Remove empty structures by using 'purify' function as in this example:
711
+
712
+
713
+ ### store.like ()
714
+ String search in dt-line name
325
715
 
326
716
  ```js
327
- const test = {
328
- name : 'Peter'
329
- , arr : [ 1, 15 ]
330
- , de : { me: ['eho', 'ha'] }
331
- , se : { le: {} }
332
- , ze : []
333
- };
334
- dtbox
335
- .init ( test )
336
- .select ()
337
- .all ()
338
- .purify ()
339
- .spread ( 'std', x => {
340
- /** Result after purify will be:
341
- * x = {
342
- * name: Peter
343
- * , arr : [1,15]
344
- * , de : { me: ['eho','ha']}
345
- * }
346
- */
347
- })
348
- }) // it purify
717
+ const data = {
718
+ name: 'Peter'
719
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
720
+ , personal : {
721
+ age : 49
722
+ , eyes : 'blue'
723
+ , sizes : [ 10, 44, 'm', 'mid' ]
724
+ , hobbies : {
725
+ music : [ 'punk', 'ska', 'metal', 'guitar' ]
726
+ , sport : [ 'fencing', 'skating', 'ski' ]
727
+ }
728
+ }
729
+ };
730
+ const
731
+ dt = dtbox.init ( data )
732
+ , res = dt.query ( store => {
733
+ store
734
+ .like ( 'per' )
735
+ .look ( ({flatData, breadcrumbs, next }) => {
736
+ console.log ( flatData )
737
+ // -> { age: 49, eyes: 'blue' }
738
+ console.log ( breadcrumbs )
739
+ // -> 'root/personal'
740
+ return next () // because we want to iterate once on each dt-line
741
+ })
742
+ });
349
743
  ```
350
744
 
351
745
 
352
- ## Data-types
353
746
 
354
- The library can spread data-selection as different data-types. Let's see how initial data will be interpreted in available data-types. Here is our initial `standard`(std) data:
747
+ // DT-model structure and fields creation:
748
+ ### store.set ()
749
+ Define new dt-line record
750
+
355
751
  ```js
356
752
  const data = {
357
- name: 'Peter'
358
- , familyMembers : [ 'Veselina', 'Iskra', 'Maria', 'Vasil', 'Vladimir', 'Petya' ]
359
- , shoes : {
360
- winter : [ 'Keen', 'Head']
361
- , summer : [ 'Lotto', 'Asics' ]
362
- }
753
+ name: 'Peter'
754
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
755
+ , personal : {
756
+ age : 49
757
+ , eyes : 'blue'
758
+ , sizes : [ 10, 44, 'm', 'mid' ]
759
+ , hobbies : {
760
+ music : [ 'punk', 'ska', 'metal', 'guitar' ]
761
+ , sport : [ 'fencing', 'skating', 'ski' ]
762
+ }
763
+ }
764
+ };
765
+ const dt = dtbox.init ( data );
766
+
767
+ const result = dt
768
+ .query ( store => {
769
+ store.set ( 'root', [2,4,15]) // new dt-line structure was created
770
+ })
771
+ .model ( () => ({as:'std'}) )
772
+ console.log ( result )
773
+ // -> [2,4,15]
774
+
775
+ const result2 = dt
776
+ .query ( store => {}) // If there is no new dt-line, query will return itself
777
+ .model ( () => ({as:'std'}) )
778
+ console.log ( result2 )
779
+ /**
780
+ {
781
+ name: 'Peter'
782
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
783
+ , personal : {
784
+ age : 49
785
+ , eyes : 'blue'
786
+ , sizes : [ 10, 44, 'm', 'mid' ]
787
+ , hobbies : {
788
+ music : [ 'punk', 'ska', 'metal', 'guitar' ]
789
+ , sport : [ 'fencing', 'skating', 'ski' ]
790
+ }
791
+ }
363
792
  }
793
+ */
364
794
  ```
365
795
 
366
- ### Standard ( std )
367
- Standard data-type will look exactly as initial data.
796
+
797
+
798
+ ### store.connect ()
799
+ Creates a list of connections between two already existing dt-lines
800
+
368
801
  ```js
369
- {
370
- name: 'Peter'
371
- , familyMembers : [ 'Veselina', 'Iskra', 'Maria', 'Vasil', 'Vladimir', 'Petya' ]
372
- , shoes : {
373
- winter : [ 'Keen', 'Head']
374
- , summer : [ 'Lotto', 'Asics' ]
375
- }
376
- }
802
+ const data = {
803
+ name: 'Peter'
804
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
805
+ };
806
+ const
807
+ dt = dtbox.init ( data )
808
+ , result = dt
809
+ .query ( store => {
810
+ store.set ( 'root', { name: Stefan })
811
+ store.set ( 'friends', [ 'Stefan', 'Tommy', 'Maria'] )
812
+ store.connect (['root/friends'])
813
+ })
814
+ .model ( () => ({as:'std'}))
815
+ ;
816
+ console.log ( result )
817
+ /**
818
+ {
819
+ name: Stefan
820
+ , friends: ['Stefan', 'Tommy', 'Maria' ]
821
+ }
822
+ */
823
+ ```
824
+
825
+
826
+
827
+ ### store.save ()
828
+ Save a property to flatData object in existing dt-line.
829
+
830
+ ```js
831
+ const data = {
832
+ name: 'Peter'
833
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
834
+ };
835
+ const
836
+ dt = dtbox.init ( data )
837
+ , result = dt
838
+ .query ( store => {
839
+ store.set ( 'root', { name: Stefan })
840
+ store.set ( 'friends', [ 'Stefan', 'Tommy', 'Maria'] )
841
+ store.connect (['root/friends'])
842
+ store.save ( 'root', 'age', 35 )
843
+ })
844
+ .model ( () => ({as:'std'}))
845
+ ;
846
+ console.log ( result )
847
+ /**
848
+ {
849
+ name: Stefan
850
+ , age : 35
851
+ , friends: ['Stefan', 'Tommy', 'Maria' ]
852
+ }
853
+ */
377
854
  ```
378
855
 
379
856
 
380
- ### Flat ( shortFlat )
381
- It's a flat description of the object. It's an array with two elements. First element describes the structure of the object, second element - the values.
382
- **Structure**: Array of flatDescriptions. FlatDescription is array where first element is the type of the object (object or array), second is the index. If there are more then 2 elements, we have connection descriptions. ConnectionDescription is array of 2 elements. First is the index of connected other object, second is the property name of the connection.
383
- In our example: We have object, that have property `familyMembers` that is array and other property `shoes` that is an object. Object `shoes` have 2 properties (winter,summer) that are arrays.
384
- **Value**: Key describes the position of the property that have a primitive value. Value is just that primitive value. Key always have 3 elements separated by '/'. First element is always `root`, second is the `id` of the object (from structure description), third is the name of the property. If structure object is 'array' then property name will be a number representing the position into the array.
857
+
858
+ ### store.push ()
859
+ Save a value to flatData of existing dt-line. FlatData should be an array.
860
+
385
861
  ```js
386
- [
387
- // the structure description
388
- [
389
- [ 'object', 0, [1,'familyMembers'], [2,'shoes'] ]
390
- , [ 'array' , 1 ]
391
- , [ 'object', 2 , [3, 'winter'], [4, 'summer'] ]
392
- , [ 'array' , 3 ]
393
- , [ 'array' , 4 ]
394
- ]
395
- // the value description
396
- , {
397
- 'root/0/name' : 'Peter'
398
- , 'root/1/0' : 'Veselina'
399
- , 'root/1/0' : 'Veselina'
400
- , 'root/1/1' : 'Iskra'
401
- , 'root/1/2' : 'Maria'
402
- , 'root/1/3' : 'Vasil'
403
- , 'root/1/4' : 'Vladimir'
404
- , 'root/1/5' : 'Petya'
405
- , 'root/3/0' : 'Keen'
406
- , 'root/3/1' : 'Head'
407
- , 'root/4/0' : 'Lotto'
408
- , 'root/4/1' : 'Asics'
409
- }
410
- ]
862
+ const data = {
863
+ name: 'Peter'
864
+ , friends : [ 'Ivan', 'Dobroslav', 'Stefan' ]
865
+ };
866
+ const
867
+ dt = dtbox.init ( data )
868
+ , result = dt
869
+ .query ( store => {
870
+ store.set ( 'root', { name: Stefan })
871
+ store.set ( 'friends', [ 'Stefan', 'Tommy', 'Maria'] )
872
+ store.connect (['root/friends'])
873
+ store.push ( 'friends', 'Lily' )
874
+ })
875
+ .model ( () => ({as:'std'}))
876
+ ;
877
+ console.log ( result )
878
+ /**
879
+ {
880
+ name: Stefan
881
+ , friends: ['Stefan', 'Tommy', 'Maria', 'Lily' ]
882
+ }
883
+ */
411
884
  ```
412
885
 
413
886
 
887
+
888
+
889
+
890
+
891
+
892
+
893
+
894
+
895
+ ## Init/Export Data-Models
896
+ The library has some predefined data-models and can read and convert data among them.
897
+
898
+ ### Standard ( std )
899
+ Standard data model is a standard deep javascript object.
900
+ ```js
901
+ const data = {
902
+ name: 'Peter'
903
+ , familyMembers : [ 'Veselina', 'Iskra', 'Maria', 'Vasil', 'Vladimir', 'Petya' ]
904
+ , shoes : {
905
+ winter : [ 'Keen', 'Head']
906
+ , summer : [ 'Lotto', 'Asics' ]
907
+ }
908
+ }
909
+ ```
910
+
414
911
  ### MidFlat
415
- Object where keys represents "location" of the flat object. Value is always an object. Props are names. If data-structure is array, props are numbers:
912
+ It's a two level deep javascript object. First object properties represent the location of the data, value is a flat object or array:
416
913
 
417
914
  ```js
418
915
  {
419
916
  'root' : { name: 'Peter' }
420
- , 'root/familyMembers' : {
421
- '0' : 'Veselina'
422
- , '1' : 'Iskra'
423
- , '2' : 'Maria'
424
- , '3' : 'Vasil'
425
- , '4' : 'Vladimir'
426
- , '5' : 'Petya'
427
- }
428
- , 'root/shoes/winter' : {
429
- '0' : 'Keen'
430
- , '1' : 'Head'
431
- }
432
- , 'root/shoes/summer' : {
433
- '0' : 'Lotto'
434
- '1' : 'Asics'
435
- }
917
+ , 'familyMembers' : ['Veselina', 'Iskra', 'Maria', 'Vasil', 'Vladimir', 'Petya' ]
918
+ , 'shoes/winter' : [ 'Keen', 'Head' ]
919
+ , 'shoes/summer' : [ 'Lotto', 'Asics' ]
436
920
  }
437
921
  ```
438
922
 
439
923
 
440
924
 
441
-
442
-
443
925
  ### Breadcrumbs
444
-
445
926
  It's a flat interpratation of the data and looks like this:
927
+
446
928
  ```js
447
929
  {
448
- 'root/name' : 'Peter'
449
- , 'root/familiMembers/0' : 'Veselina'
450
- , 'root/familyMembers/1' : 'Iskra'
451
- , 'root/familyMembers/2' : 'Maria'
452
- , 'root/familyMembers/3' : 'Vasil'
453
- , 'root/familyMembers/4' : 'Vladimir'
454
- , 'root/familyMembers/5' : 'Petya'
455
- , 'root/shoes/winter/0' : 'Keen'
456
- , 'root/shoes/winter/1' : 'Head'
457
- , 'root/shoes/summer/0' : 'Lotto'
458
- , 'root/shoes/summer/1' : 'Asics'
930
+ 'name' : 'Peter'
931
+ , 'familyMembers/0' : 'Veselina'
932
+ , 'familyMembers/1' : 'Iskra'
933
+ , 'familyMembers/2' : 'Maria'
934
+ , 'familyMembers/3' : 'Vasil'
935
+ , 'familyMembers/4' : 'Vladimir'
936
+ , 'familyMembers/5' : 'Petya'
937
+ , 'shoes/winter/0' : 'Keen'
938
+ , 'shoes/winter/1' : 'Head'
939
+ , 'shoes/summer/0' : 'Lotto'
940
+ , 'shoes/summer/1' : 'Asics'
459
941
  }
460
942
  ```
461
943
 
462
-
463
944
  ### Files
464
945
  Data is interpreted like file/folder description.
946
+
465
947
  ```js
466
948
  [
467
- 'root/name/Peter'
468
- , 'root/familiMembers/Veselina'
469
- , 'root/familyMembers/Iskra'
470
- , 'root/familyMembers/Maria'
471
- , 'root/familyMembers/Vasil'
472
- , 'root/familyMembers/Vladimir'
473
- , 'root/familyMembers/Petya'
474
- , 'root/shoes/winter/Keen'
475
- , 'root/shoes/winter/Head'
476
- , 'root/shoes/summer/Lotto'
477
- , 'root/shoes/summer/Asics'
949
+ 'name/Peter'
950
+ , 'familyMembers/Veselina'
951
+ , 'familyMembers/Iskra'
952
+ , 'familyMembers/Maria'
953
+ , 'familyMembers/Vasil'
954
+ , 'familyMembers/Vladimir'
955
+ , 'familyMembers/Petya'
956
+ , 'shoes/winter/Keen'
957
+ , 'shoes/winter/Head'
958
+ , 'shoes/summer/Lotto'
959
+ , 'shoes/summer/Asics'
478
960
  ]
479
961
  ```
480
962
 
481
-
482
-
483
963
  ### Tuples
484
964
 
485
965
  Array of tuples. First element represents location + property name, second is the value.
@@ -487,7 +967,7 @@ Array of tuples. First element represents location + property name, second is th
487
967
  ```js
488
968
  [
489
969
  ['name', 'Peter' ]
490
- , ['familiMembers', 'Veselina']
970
+ , ['familyMembers', 'Veselina']
491
971
  , ['familyMembers', 'Iskra']
492
972
  , ['familyMembers', 'Maria']
493
973
  , ['familyMembers', 'Vasil']
@@ -501,25 +981,195 @@ Array of tuples. First element represents location + property name, second is th
501
981
  ```
502
982
 
503
983
 
984
+ ## Examples
504
985
 
986
+ ### Find people under 40
505
987
 
988
+ Find a people that are under 40 years old and provide the result as a list.
506
989
 
507
- ## External Links
990
+ ```js
991
+ let data = {
992
+ 'school' : [
993
+ { name: 'Ivan', age: 14 }
994
+ , { name: 'Georgy', age: 15 }
995
+ , { name: 'Adi', age: 11 }
996
+ , { name: 'Kati', age: 11 }
997
+ ]
998
+ , 'sports' : [
999
+ { name: 'Iva', age: 28 }
1000
+ , { name: 'Stoyan', age: 36, sport: 'fencing' }
1001
+ ]
1002
+ , 'work' : [
1003
+ { name: 'Hristo', age: 38 }
1004
+ , { name: 'Lachezar', age: 33 }
1005
+ , { name: 'Veselina', age: 35 }
1006
+
1007
+ ]
1008
+ , 'recent' : {
1009
+ 'classmates' : [
1010
+ { name: 'Anton', age: 42 }
1011
+ , { name: 'Miroslava', age: 42 }
1012
+ ]
1013
+ , 'social' : [
1014
+ { name: 'Iliana', age: 61 }
1015
+ , { name: 'Tzvetan', age: 19 }
1016
+ ]
1017
+ }
1018
+ }
1019
+
1020
+ const dt = dtbox.init ( data ); // creates a dt-object
1021
+
1022
+ const result = dt.query ( store => {
1023
+ let
1024
+ i = 0
1025
+ , connectBuffer = []
1026
+ ;
1027
+ store.set ( 'root', []) // setup a root array element
1028
+ store
1029
+ .use ( 'listObject' ) // use only objects that are members of array
1030
+ .look ( ({ name, flatData, next }) => {
1031
+ if ( flatData.age < 40 ) {
1032
+ store.set ( i, flatData )
1033
+ connectBuffer.push ( `root/${i}` )
1034
+ i++
1035
+ }
1036
+ return next ()
1037
+ })
1038
+ store.connect ( connectBuffer )
1039
+ })
1040
+ .model ( () => ({ as : 'std'}))
1041
+ console.log ( result )
1042
+ /** ->
1043
+ [
1044
+ { name: 'Ivan', age: 14 },
1045
+ { name: 'Georgy', age: 15 },
1046
+ { name: 'Adi', age: 11 },
1047
+ { name: 'Kati', age: 11 },
1048
+ { name: 'Iva', age: 28 },
1049
+ { name: 'Stoyan', age: 36, sport: 'fencing' },
1050
+ { name: 'Hristo', age: 38 },
1051
+ { name: 'Lachezar', age: 33 },
1052
+ { name: 'Veselina', age: 35 },
1053
+ { name: 'Tzvetan', age: 19 }
1054
+ ]
1055
+ */
1056
+ ```
1057
+ ### Provide just a list of names
1058
+ Use the same data from previous example but return only the list of names.
1059
+
1060
+ ```js
1061
+ const result = dt.query ( store => {
1062
+ store.set ( 'root', [])
1063
+ store
1064
+ .use ( 'listObject' ) // use only objects that are members of array
1065
+ .look ( ({ flatData, next }) => {
1066
+ if ( flatData.age < 40 ) store.push ( 'root', flatData.name )
1067
+ return next ()
1068
+ })
1069
+ })
1070
+ .model ( () => ({as:'std'}) )
1071
+ console.log ( result )
1072
+ /** ->
1073
+ [
1074
+ 'Ivan', 'Georgy',
1075
+ 'Adi', 'Kati',
1076
+ 'Iva', 'Stoyan',
1077
+ 'Hristo', 'Lachezar',
1078
+ 'Veselina', 'Tzvetan'
1079
+ ]
1080
+ */
1081
+ ```
1082
+
1083
+ ### Organize people in two groups
1084
+ Return an object with two groups
1085
+ - 'over40'
1086
+ - 'under40'
1087
+ Provide only the names.
1088
+ ```js
1089
+ const result = dt.query ( store => {
1090
+ store.set ( 'root', {} )
1091
+ store.set ( 'under40', [])
1092
+ store.set ( 'over40' , [])
1093
+ store.connect ([ 'root/under40', 'root/over40' ])
1094
+ store
1095
+ .use ( 'listObject' ) // use only objects that are members of array
1096
+ .look ( ({ flatData, next }) => {
1097
+ let location = ( flatData.age > 40 ) ? 'over40' : 'under40';
1098
+ store.push ( location, flatData.name )
1099
+ return next ()
1100
+ })
1101
+ })
1102
+ .model ( () => ({ as : 'std'}))
1103
+ console.log ( result )
1104
+ /** ->
1105
+ {
1106
+ 'under40': [
1107
+ 'Ivan', 'Georgy',
1108
+ 'Adi', 'Kati',
1109
+ 'Iva', 'Stoyan',
1110
+ 'Hristo', 'Lachezar',
1111
+ 'Veselina', 'Tzvetan'
1112
+ ],
1113
+ 'over40': [ 'Anton', 'Miroslava', 'Iliana' ]
1114
+ }
1115
+ */
1116
+ ```
1117
+
1118
+
1119
+ ### Create a deep copy of dt-object
508
1120
 
1121
+ ```js
1122
+ const result = dt.query ( store => {
1123
+ store.look ( ({ name, flatData, breadcrumbs, next }) => {
1124
+ store.set ( name, flatData )
1125
+ if ( breadcrumbs.includes('/') ) store.connect ([breadcrumbs])
1126
+ return next ()
1127
+ })
1128
+ })
1129
+ .model ( () => ({as:'std'}))
1130
+ console.log ( result )
1131
+ /** ->
1132
+ {
1133
+ school: [
1134
+ { name: 'Ivan', age: 14 },
1135
+ { name: 'Georgy', age: 15 },
1136
+ { name: 'Adi', age: 11 },
1137
+ { name: 'Kati', age: 11 }
1138
+ ],
1139
+ sports: [
1140
+ { name: 'Iva', age: 28 },
1141
+ { name: 'Stoyan', age: 36, sport: 'fencing' }
1142
+ ],
1143
+ work: [
1144
+ { name: 'Hristo', age: 38 },
1145
+ { name: 'Lachezar', age: 33 },
1146
+ { name: 'Veselina', age: 35 }
1147
+ ],
1148
+ recent: {
1149
+ classmates: [ { name: 'Anton', age: 42 }, { name: 'Miroslava', age: 42 } ],
1150
+ social: [ { name: 'Iliana', age: 61 }, { name: 'Tzvetan', age: 19 } ]
1151
+ }
1152
+ }
1153
+ */
1154
+ ```
1155
+
1156
+
1157
+
1158
+
1159
+ ## External Links
509
1160
  - [Migration guide](https://github.com/PeterNaydenov/dt-toolbox/blob/master/Migration.guide.md)
510
1161
  - [History of changes](https://github.com/PeterNaydenov/dt-toolbox/blob/master/Changelog.md)
1162
+ - [DT-Queries. Some useful query functions for DT-Toolbox](https://github.com/PeterNaydenov/dt-queries)
1163
+ - [Documentation v.4.x.x](https://github.com/PeterNaydenov/dt-toolbox/blob/master/README_v.4.x.x.md)
511
1164
  - [Documentation v.2.x.x](https://github.com/PeterNaydenov/dt-toolbox/blob/master/README_v.2.x.x.md)
512
1165
 
513
1166
 
514
1167
 
515
-
516
1168
  ## Credits
517
1169
  'dt-toolbox' was created and supported by Peter Naydenov.
518
1170
 
519
1171
 
520
1172
 
521
-
522
-
523
1173
  ## License
524
1174
  'dt-toolbox' is released under the [MIT License](http://opensource.org/licenses/MIT).
525
1175