orange-orm 4.3.0 → 4.4.0-beta.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.
package/src/getManyDto.js CHANGED
@@ -19,62 +19,92 @@ async function getManyDto(table, filter, strategy, spanFromParent) {
19
19
  return decode(strategy, span, await res[0]);
20
20
  }
21
21
 
22
+ // function newCreateRow(span) {
23
+ // let columnsMap = span.columns;
24
+ // const columns = span.table._columns.filter(column => !columnsMap || columnsMap.get(column));
25
+ // const protoRow = createProto(columns, span);
26
+ // const manyNames = [];
27
+
28
+ // const c = {};
29
+ // c.visitJoin = () => { };
30
+ // c.visitOne = () => { };
31
+ // c.visitMany = function(leg) {
32
+ // manyNames.push(leg.name);
33
+ // };
34
+
35
+ // span.legs.forEach(onEachLeg);
36
+ // return createRow;
37
+
38
+ // function onEachLeg(leg) {
39
+ // leg.accept(c);
40
+ // }
41
+
42
+ // function createRow() {
43
+ // const obj = Object.create(protoRow);
44
+ // for (let i = 0; i < manyNames.length; i++) {
45
+ // obj[manyNames[i]] = [];
46
+ // }
47
+ // return obj;
48
+ // }
49
+ // }
50
+
51
+
22
52
  function newCreateRow(span) {
23
- let columnsMap = span.columns;
53
+ const columnsMap = span.columns;
24
54
  const columns = span.table._columns.filter(column => !columnsMap || columnsMap.get(column));
25
- const protoRow = createProto(columns, span);
55
+ const ProtoRow = createProto(columns, span);
26
56
  const manyNames = [];
27
57
 
28
- const c = {};
29
- c.visitJoin = () => { };
30
- c.visitOne = () => { };
31
- c.visitMany = function(leg) {
32
- manyNames.push(leg.name);
58
+ const c = {
59
+ visitJoin: () => { },
60
+ visitOne: () => { },
61
+ visitMany: function(leg) {
62
+ manyNames.push(leg.name);
63
+ }
33
64
  };
34
65
 
35
- span.legs.forEach(onEachLeg);
36
- return createRow;
66
+ span.legs.forEach(leg => leg.accept(c));
37
67
 
38
- function onEachLeg(leg) {
39
- leg.accept(c);
40
- }
68
+ return createRow;
41
69
 
42
70
  function createRow() {
43
- const obj = Object.create(protoRow);
44
- for (let i = 0; i < manyNames.length; i++) {
45
- obj[manyNames[i]] = [];
46
- }
71
+ const obj = new ProtoRow();
72
+ manyNames.forEach(name => {
73
+ obj[name] = [];
74
+ });
47
75
  return obj;
48
76
  }
49
77
  }
50
78
 
51
79
  function createProto(columns, span) {
52
- let obj = {};
53
- for (let i = 0; i < columns.length; i++) {
54
- obj[columns[i].alias] = null;
55
- }
56
- for (let key in span.aggregates) {
57
- obj[key] = null;
58
- }
59
- const c = {};
80
+ function ProtoRow() {
81
+ columns.forEach(column => {
82
+ this[column.alias] = null;
83
+ });
60
84
 
61
- c.visitJoin = function(leg) {
62
- obj[leg.name] = null;
63
- };
64
- c.visitOne = c.visitJoin;
65
- c.visitMany = function(leg) {
66
- obj[leg.name] = null;
67
- };
85
+ for (const key in span.aggregates) {
86
+ this[key] = null;
87
+ }
68
88
 
69
- span.legs.forEach(onEachLeg);
89
+ const c = {
90
+ visitJoin: (leg) => {
91
+ this[leg.name] = null;
92
+ },
93
+ visitOne: (leg) => {
94
+ this[leg.name] = null;
95
+ },
96
+ visitMany: (leg) => {
97
+ this[leg.name] = null;
98
+ }
99
+ };
70
100
 
71
- function onEachLeg(leg) {
72
- leg.accept(c);
101
+ span.legs.forEach(leg => leg.accept(c));
73
102
  }
74
103
 
75
- return obj;
104
+ return ProtoRow;
76
105
  }
77
106
 
107
+
78
108
  function hasManyRelations(span) {
79
109
  let result;
80
110
  const c = {};
@@ -92,7 +122,7 @@ function hasManyRelations(span) {
92
122
  }
93
123
  }
94
124
 
95
- async function decode(strategy, span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) : []) {
125
+ async function decode(strategy, span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) : [], parentRows, parentProp) {
96
126
  const table = span.table;
97
127
  let columnsMap = span.columns;
98
128
  const columns = table._columns.filter(column => !columnsMap || columnsMap.get(column));
@@ -132,9 +162,11 @@ async function decode(strategy, span, rows, keys = rows.length > 0 ? Object.keys
132
162
  }
133
163
 
134
164
  outRows[i] = outRow;
165
+ if (parentRows)
166
+ parentRows[i][parentProp] = outRow;
135
167
  if (shouldCreateMap) {
136
168
  fkIds[i] = getIds(outRow);
137
- addToMap(rowsMap, primaryColumns, outRow);
169
+ addToMap(rowsMap, fkIds[i], outRow);
138
170
  }
139
171
  }
140
172
  span._rowsMap = rowsMap;
@@ -185,18 +217,38 @@ async function decodeManyRelations(strategy, span) {
185
217
  const name = leg.name;
186
218
  const table = span.table;
187
219
  const relation = table._relations[name];
188
- const filter = createOneFilter(relation, span._ids);
189
220
  const rowsMap = span._rowsMap;
221
+
222
+ const filter = createOneFilter(relation, span._ids);
223
+ const extractKey = createExtractKey(leg);
224
+ const extractFromMap = createExtractFromMap(rowsMap, table._primaryColumns);
190
225
  const p = getManyDto(relation.childTable, filter, strategy[name], leg.span).then(subRows => {
191
226
  for (let i = 0; i < subRows.length; i++) {
192
- const key = leg.columns.map(column => subRows[i][column.alias]);
193
- const parentRow = getFromMap(rowsMap, table._primaryColumns, key);
227
+ const key = extractKey(subRows[i]);
228
+ const parentRow = extractFromMap(key);
194
229
  parentRow[name].push(subRows[i]);
195
230
  }
196
231
  });
197
232
  promises.push(p);
198
233
  };
199
234
 
235
+ function createExtractKey(leg) {
236
+ if (leg.columns.length === 1) {
237
+ const alias = leg.columns[0].alias;
238
+ return (row) => row[alias];
239
+ }
240
+ else {
241
+ const aliases = leg.columns.map(column => column.alias);
242
+ return (row) => aliases.map(alias => row[alias]);
243
+ }
244
+ }
245
+ function createExtractFromMap(map, primaryColumns) {
246
+ if (primaryColumns.length === 1)
247
+ return (key) => map.get(key);
248
+ else
249
+ return getFromMap.bind(null, map, primaryColumns);
250
+ }
251
+
200
252
  span.legs.forEach(onEachLeg);
201
253
 
202
254
  function onEachLeg(leg) {
@@ -211,11 +263,7 @@ async function decodeRelations2(strategy, span, rawRows, resultRows, keys) {
211
263
  const c = {};
212
264
  c.visitJoin = function(leg) {
213
265
  const name = leg.name;
214
- const p = decode(strategy[name], leg.span, rawRows, keys).then((rows) => {
215
- for (let i = 0; i < rows.length; i++) {
216
- resultRows[i][name] = rows[i];
217
- }
218
- });
266
+ const p = decode(strategy[name], leg.span, rawRows, keys, resultRows, name);
219
267
  promises.push(p);
220
268
  };
221
269
 
@@ -233,47 +281,6 @@ async function decodeRelations2(strategy, span, rawRows, resultRows, keys) {
233
281
  await Promise.all(promises);
234
282
  }
235
283
 
236
-
237
- // async function decodeRelations(strategy, span, rawRows, resultRows, keys) {
238
- // const promises = [];
239
- // const c = {};
240
- // c.visitJoin = function (leg) {
241
- // const name = leg.name;
242
- // const p = decode(strategy[name], leg.span, rawRows, keys).then((rows) => {
243
- // for (let i = 0; i < rows.length; i++) {
244
- // resultRows[i][name] = rows[i];
245
- // }
246
- // });
247
- // promises.push(p);
248
- // };
249
-
250
- // c.visitOne = c.visitJoin;
251
-
252
- // c.visitMany = function (leg) {
253
- // const name = leg.name;
254
- // const table = span.table;
255
- // const relation = table._relations[name];
256
- // const filter = createOneFilter(relation, span._ids);
257
- // const rowsMap = span._rowsMap;
258
- // const p = getManyDto(relation.childTable, filter, strategy[name], leg.span).then(subRows => {
259
- // for (let i = 0; i < subRows.length; i++) {
260
- // const key = leg.columns.map(column => subRows[i][column.alias]);
261
- // const parentRow = getFromMap(rowsMap, table._primaryColumns, key);
262
- // parentRow[name].push(subRows[i]);
263
- // }
264
- // });
265
- // promises.push(p);
266
- // };
267
-
268
- // span.legs.forEach(onEachLeg);
269
-
270
- // function onEachLeg(leg) {
271
- // leg.accept(c);
272
- // }
273
-
274
- // await Promise.all(promises);
275
- // }
276
-
277
284
  function createOneFilter(relation, ids) {
278
285
  const columns = relation.joinRelation.columns;
279
286
 
@@ -299,28 +306,36 @@ function createOneFilter(relation, ids) {
299
306
  }
300
307
  }
301
308
 
302
- function addToMap(map, primaryColumns, row) {
303
-
304
- const lastIndex = primaryColumns.length - 1;
305
- for (let i = 0; i < lastIndex; i++) {
306
- const id = row[primaryColumns[i].alias];
307
- if (map.has(id))
308
- map = map.get(id);
309
- else {
310
- const next = new Map();
311
- map.set(id, next);
312
- map = next;
309
+ function addToMap(map, values, row) {
310
+ if (Array.isArray(values)) {
311
+
312
+ const lastIndex = values.length - 1;
313
+ for (let i = 0; i < lastIndex; i++) {
314
+ const id = values[i];
315
+ if (map.has(id))
316
+ map = map.get(id);
317
+ else {
318
+ const next = new Map();
319
+ map.set(id, next);
320
+ map = next;
321
+ }
313
322
  }
323
+ map.set(values[lastIndex], row);
314
324
  }
315
- map.set(row[primaryColumns[lastIndex].alias], row);
325
+ else
326
+ map.set(values, row);
316
327
  }
317
328
 
318
329
  function getFromMap(map, primaryColumns, values) {
319
- const length = primaryColumns.length;
320
- for (let i = 0; i < length; i++) {
321
- map = map.get(values[i]);
330
+ if (Array.isArray(values)) {
331
+ const length = primaryColumns.length;
332
+ for (let i = 0; i < length; i++) {
333
+ map = map.get(values[i]);
334
+ }
335
+ return map;
322
336
  }
323
- return map;
337
+ else
338
+ return map.get(values);
324
339
  }
325
340
 
326
341
 
@@ -0,0 +1,293 @@
1
+ const emptyFilter = require('./emptyFilter');
2
+ const newQuery = require('./getManyDto/newQuery');
3
+ const negotiateRawSqlFilter = require('./table/column/negotiateRawSqlFilter');
4
+ const strategyToSpan = require('./table/strategyToSpan');
5
+ const executeQueries = require('./table/executeQueries');
6
+
7
+ async function getManyDto(table, filter, strategy, spanFromParent) {
8
+ filter = negotiateRawSqlFilter(filter, table);
9
+ if (strategy && strategy.where) {
10
+ let arg = typeof strategy.where === 'function' ? strategy.where(table) : strategy.where;
11
+ filter = filter.and(arg);
12
+ }
13
+
14
+ let span = spanFromParent || strategyToSpan(table, strategy);
15
+ let alias = table._dbName;
16
+
17
+ const query = newQuery(table, filter, span, alias);
18
+ const res = await executeQueries([query]);
19
+ return decode(strategy, span, await res[0]);
20
+ }
21
+
22
+ function newCreateRow(span) {
23
+ let columnsMap = span.columns;
24
+ const columns = span.table._columns.filter(column => !columnsMap || columnsMap.get(column));
25
+ const protoRow = createProto(columns, span);
26
+ const manyNames = [];
27
+
28
+ const c = {};
29
+ c.visitJoin = () => { };
30
+ c.visitOne = () => { };
31
+ c.visitMany = function (leg) {
32
+ manyNames.push(leg.name);
33
+ };
34
+
35
+ span.legs.forEach(onEachLeg);
36
+ return createRow;
37
+
38
+ function onEachLeg(leg) {
39
+ leg.accept(c);
40
+ }
41
+
42
+ function createRow() {
43
+ const obj = Object.create(protoRow);
44
+ for (let i = 0; i < manyNames.length; i++) {
45
+ obj[manyNames[i]] = [];
46
+ }
47
+ return obj;
48
+ }
49
+ }
50
+
51
+ function createProto(columns, span) {
52
+ let obj = {};
53
+ for (let i = 0; i < columns.length; i++) {
54
+ obj[columns[i].alias] = null;
55
+ }
56
+ for (let key in span.aggregates) {
57
+ obj[key] = null;
58
+ }
59
+ const c = {};
60
+
61
+ c.visitJoin = function (leg) {
62
+ obj[leg.name] = null;
63
+ };
64
+ c.visitOne = c.visitJoin;
65
+ c.visitMany = function (leg) {
66
+ obj[leg.name] = null;
67
+ };
68
+
69
+ span.legs.forEach(onEachLeg);
70
+
71
+ function onEachLeg(leg) {
72
+ leg.accept(c);
73
+ }
74
+
75
+ return obj;
76
+ }
77
+
78
+ function hasManyRelations(span) {
79
+ let result;
80
+ const c = {};
81
+ c.visitJoin = () => { };
82
+ c.visitOne = c.visitJoin;
83
+ c.visitMany = function () {
84
+ result = true;
85
+ };
86
+
87
+ span.legs.forEach(onEachLeg);
88
+ return result;
89
+
90
+ function onEachLeg(leg) {
91
+ leg.accept(c);
92
+ }
93
+ }
94
+
95
+ async function decode(strategy, span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) : []) {
96
+ const table = span.table;
97
+ let columnsMap = span.columns;
98
+ const columns = table._columns.filter(column => !columnsMap || columnsMap.get(column));
99
+ const rowsLength = rows.length;
100
+ const columnsLength = columns.length;
101
+ const primaryColumns = table._primaryColumns;
102
+ const primaryColumnsLength = primaryColumns.length;
103
+ const rowsMap = new Map();
104
+ const fkIds = new Array(rows.length);
105
+ const getIds = createGetIds();
106
+ const aggregateKeys = Object.keys(span.aggregates);
107
+
108
+ const outRows = new Array(rowsLength);
109
+ const createRow = newCreateRow(span);
110
+ const shouldCreateMap = hasManyRelations(span);
111
+ const promises = [];
112
+ for (let i = 0; i < rowsLength; i++) {
113
+ const row = rows[i];
114
+ let outRow = createRow();
115
+ let pkWithNullCount = 0;
116
+ for (let j = 0; j < primaryColumnsLength; j++) {
117
+ if (row[keys[j]] === null)
118
+ pkWithNullCount++;
119
+ if (pkWithNullCount === primaryColumnsLength) {
120
+ outRow = null;
121
+ break;
122
+ }
123
+ const column = columns[j];
124
+ outRow[column.alias] = column.decode(row[keys[j]]);
125
+ }
126
+
127
+ outRows[i] = outRow;
128
+ if (outRow === null)
129
+ continue;
130
+ if (shouldCreateMap) {
131
+ fkIds[i] = getIds(outRow);
132
+ addToMap(rowsMap, primaryColumns, outRow);
133
+ }
134
+
135
+ // Execute code inside start and stop in the next event loop and as a promise
136
+ promises.push(new Promise((resolve) => {
137
+ ((currentRow, currentOutRow) => {
138
+ setTimeout(async () => {
139
+ for (let j = primaryColumnsLength; j < columnsLength; j++) {
140
+ const column = columns[j];
141
+ currentOutRow[column.alias] = column.decode(currentRow[keys[j]]);
142
+ }
143
+
144
+ for (let j = 0; j < aggregateKeys.length; j++) {
145
+ const key = aggregateKeys[j];
146
+ const parse = span.aggregates[key].column?.decode || Number.parseFloat;
147
+ currentOutRow[key] = parse(currentRow[keys[j + columnsLength]]);
148
+ }
149
+
150
+ resolve();
151
+ }, 0);
152
+ })(row, outRow);
153
+ }));
154
+ }
155
+ span._rowsMap = rowsMap;
156
+ span._ids = fkIds;
157
+
158
+ const many = decodeManyRelations(strategy, span);
159
+
160
+ const p = Promise.all(promises).then(() => {
161
+ keys.splice(0, columnsLength + aggregateKeys.length);
162
+ return decodeRelations(strategy, span, rows, outRows, keys)
163
+ });
164
+ await Promise.all([many, p]);
165
+ return outRows;
166
+
167
+
168
+ function createGetIds() {
169
+ const primaryColumns = table._primaryColumns;
170
+ const length = primaryColumns.length;
171
+ if (length === 1) {
172
+ const alias = table._primaryColumns[0].alias;
173
+ return (row) => row[alias];
174
+ }
175
+ else
176
+ return (row) => {
177
+ const result = new Array(length);
178
+ for (let i = 0; i < length; i++) {
179
+ result[i] = row[primaryColumns[i].alias];
180
+ }
181
+ return result;
182
+ };
183
+ }
184
+
185
+ }
186
+
187
+ async function decodeManyRelations(strategy, span) {
188
+ const promises = [];
189
+ const c = {};
190
+ c.visitJoin = () => { };
191
+ c.visitOne = c.visitJoin;
192
+
193
+ c.visitMany = function (leg) {
194
+ const name = leg.name;
195
+ const table = span.table;
196
+ const relation = table._relations[name];
197
+ const filter = createOneFilter(relation, span._ids);
198
+ const rowsMap = span._rowsMap;
199
+ const p = getManyDto(relation.childTable, filter, strategy[name], leg.span).then(subRows => {
200
+ for (let i = 0; i < subRows.length; i++) {
201
+ const key = leg.columns.map(column => subRows[i][column.alias]);
202
+ const parentRow = getFromMap(rowsMap, table._primaryColumns, key);
203
+ parentRow[name].push(subRows[i]);
204
+ }
205
+ });
206
+ promises.push(p);
207
+ };
208
+
209
+ span.legs.forEach(onEachLeg);
210
+
211
+ function onEachLeg(leg) {
212
+ leg.accept(c);
213
+ }
214
+
215
+ await Promise.all(promises);
216
+ }
217
+ async function decodeRelations(strategy, span, rawRows, resultRows, keys) {
218
+ const promises = [];
219
+ const c = {};
220
+ c.visitJoin = function (leg) {
221
+ const name = leg.name;
222
+ const p = decode(strategy[name], leg.span, rawRows, keys).then((rows) => {
223
+ for (let i = 0; i < rows.length; i++) {
224
+ resultRows[i][name] = rows[i];
225
+ }
226
+ });
227
+ promises.push(p);
228
+ };
229
+
230
+ c.visitOne = c.visitJoin;
231
+
232
+ c.visitMany = () => { };
233
+
234
+ span.legs.forEach(onEachLeg);
235
+
236
+ function onEachLeg(leg) {
237
+ leg.accept(c);
238
+ }
239
+
240
+ await Promise.all(promises);
241
+ }
242
+
243
+ function createOneFilter(relation, ids) {
244
+ const columns = relation.joinRelation.columns;
245
+
246
+ if (columns.length === 1)
247
+ return columns[0].in(ids);
248
+
249
+ else
250
+ return createCompositeFilter();
251
+
252
+ function createCompositeFilter() {
253
+ let filter = emptyFilter;
254
+ for (let id of ids) {
255
+ let nextFilter;
256
+ for (let i = 0; i < columns.length; i++) {
257
+ if (nextFilter)
258
+ nextFilter = nextFilter.and(columns[i].eq(id[i]));
259
+ else
260
+ nextFilter = columns[i].eq(id[i]);
261
+ }
262
+ filter = filter.or(nextFilter);
263
+ }
264
+ return filter;
265
+ }
266
+ }
267
+
268
+ function addToMap(map, primaryColumns, row) {
269
+
270
+ const lastIndex = primaryColumns.length - 1;
271
+ for (let i = 0; i < lastIndex; i++) {
272
+ const id = row[primaryColumns[i].alias];
273
+ if (map.has(id))
274
+ map = map.get(id);
275
+ else {
276
+ const next = new Map();
277
+ map.set(id, next);
278
+ map = next;
279
+ }
280
+ }
281
+ map.set(row[primaryColumns[lastIndex].alias], row);
282
+ }
283
+
284
+ function getFromMap(map, primaryColumns, values) {
285
+ const length = primaryColumns.length;
286
+ for (let i = 0; i < length; i++) {
287
+ map = map.get(values[i]);
288
+ }
289
+ return map;
290
+ }
291
+
292
+
293
+ module.exports = getManyDto;