@sqb/connect 4.2.1 → 4.5.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 (154) hide show
  1. package/README.md +67 -0
  2. package/{dist/client/Adapter.js → cjs/client/adapter.js} +0 -0
  3. package/{dist/client/CursorStream.js → cjs/client/cursor-stream.js} +5 -2
  4. package/{dist/client/Cursor.js → cjs/client/cursor.js} +18 -11
  5. package/{dist → cjs}/client/extensions.js +0 -0
  6. package/{dist/client/FieldInfoMap.js → cjs/client/field-info-map.js} +2 -0
  7. package/{dist → cjs}/client/helpers.js +2 -2
  8. package/{dist/client/SqbClient.js → cjs/client/sqb-client.js} +16 -10
  9. package/{dist/client/SqbConnection.js → cjs/client/sqb-connection.js} +17 -14
  10. package/{dist → cjs}/client/types.js +0 -0
  11. package/cjs/index.js +42 -0
  12. package/{dist → cjs}/orm/backward.js +8 -8
  13. package/{dist → cjs}/orm/base-entity.js +8 -7
  14. package/{dist → cjs}/orm/commands/command.helper.js +9 -9
  15. package/{dist → cjs}/orm/commands/count.command.js +2 -2
  16. package/{dist → cjs}/orm/commands/create.command.js +12 -12
  17. package/{dist → cjs}/orm/commands/destroy.command.js +2 -2
  18. package/{dist → cjs}/orm/commands/find.command.js +100 -88
  19. package/{dist → cjs}/orm/commands/row-converter.js +10 -7
  20. package/{dist → cjs}/orm/commands/update.command.js +10 -10
  21. package/{dist → cjs}/orm/decorators/column.decorator.js +3 -3
  22. package/{dist → cjs}/orm/decorators/embedded.decorator.js +3 -3
  23. package/cjs/orm/decorators/entity.decorator.js +179 -0
  24. package/{dist → cjs}/orm/decorators/events.decorator.js +13 -13
  25. package/{dist → cjs}/orm/decorators/foreignkey.decorator.js +3 -3
  26. package/{dist → cjs}/orm/decorators/index.decorator.js +5 -5
  27. package/cjs/orm/decorators/link.decorator.js +70 -0
  28. package/{dist → cjs}/orm/decorators/primarykey.decorator.js +7 -7
  29. package/{dist → cjs}/orm/decorators/transform.decorator.js +5 -5
  30. package/cjs/orm/model/association-field-metadata.js +24 -0
  31. package/{dist → cjs}/orm/model/association-node.js +5 -2
  32. package/{dist → cjs}/orm/model/association.js +31 -39
  33. package/{dist/orm/model/column-element-metadata.js → cjs/orm/model/column-field-metadata.js} +8 -8
  34. package/{dist/orm/model/embedded-element-metadata.js → cjs/orm/model/embedded-field-metadata.js} +8 -8
  35. package/{dist → cjs}/orm/model/entity-metadata.js +90 -91
  36. package/{dist/orm/model/element-metadata.js → cjs/orm/model/field-metadata.js} +0 -0
  37. package/{dist → cjs}/orm/model/index-metadata.js +0 -0
  38. package/{dist → cjs}/orm/model/link-chain.js +12 -15
  39. package/{dist → cjs}/orm/orm.const.js +0 -0
  40. package/{dist → cjs}/orm/orm.type.js +0 -0
  41. package/{dist → cjs}/orm/repository.class.js +25 -22
  42. package/{dist → cjs}/orm/util/apply-mixins.js +0 -0
  43. package/{dist → cjs}/orm/util/extract-keyvalues.js +5 -5
  44. package/{dist → cjs}/orm/util/orm.helper.js +10 -10
  45. package/{dist/orm/util/serialize-element.js → cjs/orm/util/serialize-field.js} +2 -2
  46. package/cjs/package.json +3 -0
  47. package/{dist → cjs}/types.js +0 -0
  48. package/{dist/client/Adapter.d.ts → esm/client/adapter.d.ts} +1 -1
  49. package/esm/client/adapter.js +1 -0
  50. package/{dist/client/CursorStream.d.ts → esm/client/cursor-stream.d.ts} +1 -1
  51. package/esm/client/cursor-stream.js +96 -0
  52. package/{dist/client/Cursor.d.ts → esm/client/cursor.d.ts} +5 -5
  53. package/esm/client/cursor.js +252 -0
  54. package/{dist → esm}/client/extensions.d.ts +1 -1
  55. package/esm/client/extensions.js +9 -0
  56. package/{dist/client/FieldInfoMap.d.ts → esm/client/field-info-map.d.ts} +1 -1
  57. package/esm/client/field-info-map.js +50 -0
  58. package/{dist → esm}/client/helpers.d.ts +3 -3
  59. package/esm/client/helpers.js +125 -0
  60. package/{dist/client/SqbClient.d.ts → esm/client/sqb-client.d.ts} +4 -10
  61. package/esm/client/sqb-client.js +166 -0
  62. package/{dist/client/SqbConnection.d.ts → esm/client/sqb-connection.d.ts} +4 -4
  63. package/esm/client/sqb-connection.js +270 -0
  64. package/{dist → esm}/client/types.d.ts +5 -13
  65. package/esm/client/types.js +1 -0
  66. package/esm/index.d.ts +33 -0
  67. package/esm/index.js +32 -0
  68. package/{dist → esm}/orm/backward.d.ts +1 -1
  69. package/esm/orm/backward.js +17 -0
  70. package/{dist → esm}/orm/base-entity.d.ts +1 -1
  71. package/esm/orm/base-entity.js +25 -0
  72. package/{dist → esm}/orm/commands/command.helper.d.ts +2 -2
  73. package/esm/orm/commands/command.helper.js +135 -0
  74. package/{dist → esm}/orm/commands/count.command.d.ts +3 -3
  75. package/esm/orm/commands/count.command.js +26 -0
  76. package/{dist → esm}/orm/commands/create.command.d.ts +2 -2
  77. package/esm/orm/commands/create.command.js +85 -0
  78. package/{dist → esm}/orm/commands/destroy.command.d.ts +3 -3
  79. package/esm/orm/commands/destroy.command.js +26 -0
  80. package/{dist → esm}/orm/commands/find.command.d.ts +9 -9
  81. package/esm/orm/commands/find.command.js +318 -0
  82. package/{dist → esm}/orm/commands/row-converter.d.ts +5 -5
  83. package/esm/orm/commands/row-converter.js +186 -0
  84. package/{dist → esm}/orm/commands/update.command.d.ts +3 -3
  85. package/esm/orm/commands/update.command.js +80 -0
  86. package/esm/orm/decorators/column.decorator.d.ts +4 -0
  87. package/esm/orm/decorators/column.decorator.js +19 -0
  88. package/esm/orm/decorators/embedded.decorator.d.ts +3 -0
  89. package/esm/orm/decorators/embedded.decorator.js +12 -0
  90. package/{dist → esm}/orm/decorators/entity.decorator.d.ts +17 -17
  91. package/esm/orm/decorators/entity.decorator.js +175 -0
  92. package/{dist → esm}/orm/decorators/events.decorator.d.ts +0 -0
  93. package/esm/orm/decorators/events.decorator.js +55 -0
  94. package/{dist → esm}/orm/decorators/foreignkey.decorator.d.ts +1 -1
  95. package/esm/orm/decorators/foreignkey.decorator.js +9 -0
  96. package/{dist → esm}/orm/decorators/index.decorator.d.ts +1 -1
  97. package/esm/orm/decorators/index.decorator.js +17 -0
  98. package/esm/orm/decorators/link.decorator.d.ts +13 -0
  99. package/esm/orm/decorators/link.decorator.js +66 -0
  100. package/{dist → esm}/orm/decorators/primarykey.decorator.d.ts +1 -1
  101. package/esm/orm/decorators/primarykey.decorator.js +20 -0
  102. package/{dist → esm}/orm/decorators/transform.decorator.d.ts +1 -1
  103. package/esm/orm/decorators/transform.decorator.js +19 -0
  104. package/esm/orm/model/association-field-metadata.d.ts +12 -0
  105. package/esm/orm/model/association-field-metadata.js +20 -0
  106. package/{dist → esm}/orm/model/association-node.d.ts +1 -1
  107. package/esm/orm/model/association-node.js +24 -0
  108. package/{dist → esm}/orm/model/association.d.ts +6 -7
  109. package/esm/orm/model/association.js +118 -0
  110. package/{dist/orm/model/column-element-metadata.d.ts → esm/orm/model/column-field-metadata.d.ts} +10 -14
  111. package/esm/orm/model/column-field-metadata.js +28 -0
  112. package/esm/orm/model/embedded-field-metadata.d.ts +14 -0
  113. package/esm/orm/model/embedded-field-metadata.js +25 -0
  114. package/esm/orm/model/entity-metadata.d.ts +50 -0
  115. package/esm/orm/model/entity-metadata.js +337 -0
  116. package/esm/orm/model/field-metadata.d.ts +16 -0
  117. package/esm/orm/model/field-metadata.js +1 -0
  118. package/{dist → esm}/orm/model/index-metadata.d.ts +0 -0
  119. package/esm/orm/model/index-metadata.js +1 -0
  120. package/esm/orm/model/link-chain.d.ts +13 -0
  121. package/esm/orm/model/link-chain.js +43 -0
  122. package/{dist → esm}/orm/orm.const.d.ts +0 -0
  123. package/esm/orm/orm.const.js +2 -0
  124. package/{dist → esm}/orm/orm.type.d.ts +3 -4
  125. package/esm/orm/orm.type.js +1 -0
  126. package/{dist → esm}/orm/repository.class.d.ts +23 -23
  127. package/esm/orm/repository.class.js +238 -0
  128. package/{dist → esm}/orm/util/apply-mixins.d.ts +0 -0
  129. package/esm/orm/util/apply-mixins.js +9 -0
  130. package/{dist → esm}/orm/util/extract-keyvalues.d.ts +1 -1
  131. package/esm/orm/util/extract-keyvalues.js +57 -0
  132. package/esm/orm/util/orm.helper.d.ts +13 -0
  133. package/esm/orm/util/orm.helper.js +28 -0
  134. package/esm/orm/util/serialize-field.d.ts +2 -0
  135. package/esm/orm/util/serialize-field.js +39 -0
  136. package/esm/types.d.ts +7 -0
  137. package/esm/types.js +1 -0
  138. package/package.json +54 -41
  139. package/dist/index.d.ts +0 -33
  140. package/dist/index.js +0 -42
  141. package/dist/orm/decorators/column.decorator.d.ts +0 -4
  142. package/dist/orm/decorators/embedded.decorator.d.ts +0 -3
  143. package/dist/orm/decorators/entity.decorator.js +0 -179
  144. package/dist/orm/decorators/link.decorator.d.ts +0 -23
  145. package/dist/orm/decorators/link.decorator.js +0 -88
  146. package/dist/orm/model/association-element-metadata.d.ts +0 -10
  147. package/dist/orm/model/association-element-metadata.js +0 -15
  148. package/dist/orm/model/element-metadata.d.ts +0 -7
  149. package/dist/orm/model/embedded-element-metadata.d.ts +0 -14
  150. package/dist/orm/model/entity-metadata.d.ts +0 -50
  151. package/dist/orm/model/link-chain.d.ts +0 -15
  152. package/dist/orm/util/orm.helper.d.ts +0 -13
  153. package/dist/orm/util/serialize-element.d.ts +0 -2
  154. package/dist/types.d.ts +0 -2
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { Readable } from 'stream';
3
- import { Cursor } from './Cursor';
3
+ import { Cursor } from './cursor.js';
4
4
  export interface CursorStreamOptions {
5
5
  objectMode?: boolean;
6
6
  limit?: number;
@@ -0,0 +1,96 @@
1
+ import _debug from 'debug';
2
+ import { Readable } from 'stream';
3
+ const inspect = Symbol.for('nodejs.util.inspect.custom');
4
+ const debug = _debug('sqb:cursorstream');
5
+ export class CursorStream extends Readable {
6
+ _cursor;
7
+ _objectMode;
8
+ _limit;
9
+ _rowNum = -1;
10
+ _eof = false;
11
+ constructor(cursor, options) {
12
+ super(options);
13
+ this._cursor = cursor;
14
+ this._objectMode = options?.objectMode;
15
+ this._limit = options?.limit || Number.MAX_SAFE_INTEGER;
16
+ this.on('end', () => {
17
+ this.close().catch(() => false);
18
+ });
19
+ cursor.once('close', () => this.emit('close'));
20
+ cursor.on('error', (err) => this.emit('error', err));
21
+ }
22
+ /**
23
+ * Returns if stream is closed.
24
+ */
25
+ get isClosed() {
26
+ return this._cursor.isClosed;
27
+ }
28
+ /**
29
+ * Closes stream and releases the cursor
30
+ */
31
+ close() {
32
+ this.pause();
33
+ this.unpipe();
34
+ return this._cursor.close();
35
+ }
36
+ toString() {
37
+ return '[object ' + Object.getPrototypeOf(this).constructor.name + ']';
38
+ }
39
+ [inspect]() {
40
+ return this.toString();
41
+ }
42
+ _read() {
43
+ if (this._rowNum >= this._limit) {
44
+ this.pause();
45
+ this.unpipe();
46
+ this.emit('end');
47
+ return;
48
+ }
49
+ this._cursor.next().then(row => {
50
+ if (this._eof)
51
+ return this.push(null);
52
+ let buf = '';
53
+ if (this._rowNum < 0) {
54
+ this._rowNum = 0;
55
+ if (!this._objectMode)
56
+ buf += '[';
57
+ }
58
+ if (!row) {
59
+ this._eof = true;
60
+ if (!this._objectMode) {
61
+ buf += ']';
62
+ this.push(buf);
63
+ }
64
+ else
65
+ this.push(null);
66
+ return;
67
+ }
68
+ this._rowNum++;
69
+ if (this._objectMode)
70
+ this.push(row);
71
+ else {
72
+ if (this._rowNum > 1)
73
+ buf += ',';
74
+ this.push(buf + JSON.stringify(row));
75
+ }
76
+ }).catch(err => {
77
+ /* istanbul ignore next */
78
+ if (typeof this.destroy == 'function')
79
+ this.destroy(err);
80
+ else
81
+ this.emit('error', err);
82
+ this.close().catch(() => 0);
83
+ });
84
+ }
85
+ emit(event, ...args) {
86
+ try {
87
+ if (event === 'error' && !this.listenerCount('error'))
88
+ return false;
89
+ return super.emit(event, ...args);
90
+ }
91
+ catch (ignored) {
92
+ debug('emit-error', ignored);
93
+ return false;
94
+ }
95
+ }
96
+ }
@@ -1,8 +1,8 @@
1
- import { Adapter } from './Adapter';
2
- import { CursorStream, CursorStreamOptions } from './CursorStream';
3
- import { FieldInfoMap } from './FieldInfoMap';
4
- import { SqbConnection } from './SqbConnection';
5
- import { ObjectRow, QueryRequest } from './types';
1
+ import { Adapter } from './adapter.js';
2
+ import { CursorStream, CursorStreamOptions } from './cursor-stream.js';
3
+ import { FieldInfoMap } from './field-info-map.js';
4
+ import { SqbConnection } from './sqb-connection.js';
5
+ import { ObjectRow, QueryRequest } from './types.js';
6
6
  interface CursorEvents {
7
7
  close: () => void;
8
8
  error: (error: unknown) => void;
@@ -0,0 +1,252 @@
1
+ import _debug from 'debug';
2
+ import DoublyLinked from 'doublylinked';
3
+ import TaskQueue from 'putil-taskqueue';
4
+ import { coerceToInt } from 'putil-varhelpers';
5
+ import { AsyncEventEmitter, TypedEventEmitterClass } from 'strict-typed-events';
6
+ import { CursorStream } from './cursor-stream.js';
7
+ import { callFetchHooks, normalizeRowsToArrayRows, normalizeRowsToObjectRows } from './helpers.js';
8
+ const debug = _debug('sqb:cursor');
9
+ export class Cursor extends TypedEventEmitterClass(AsyncEventEmitter) {
10
+ _connection;
11
+ _fields;
12
+ _prefetchRows;
13
+ _request;
14
+ _intlcur;
15
+ _taskQueue = new TaskQueue();
16
+ _fetchCache = new DoublyLinked();
17
+ _rowNum = 0;
18
+ _fetchedAll = false;
19
+ _fetchedRows = 0;
20
+ _row;
21
+ _cache;
22
+ constructor(connection, fields, adapterCursor, request) {
23
+ super();
24
+ this._connection = connection;
25
+ this._intlcur = adapterCursor;
26
+ this._fields = fields;
27
+ this._request = request;
28
+ this._prefetchRows = request?.fetchRows || 100;
29
+ }
30
+ /**
31
+ * Returns the Connection instance
32
+ */
33
+ get connection() {
34
+ return this._connection;
35
+ }
36
+ /**
37
+ * Returns if cursor is before first record.
38
+ */
39
+ get isBof() {
40
+ return !this._rowNum;
41
+ }
42
+ /**
43
+ * Returns if cursor is closed.
44
+ */
45
+ get isClosed() {
46
+ return !this._intlcur;
47
+ }
48
+ /**
49
+ * Returns if cursor is after last record.
50
+ */
51
+ get isEof() {
52
+ return this._fetchedAll && this.rowNum > this._fetchedRows;
53
+ }
54
+ /**
55
+ * Returns number of fetched record count from database.
56
+ */
57
+ get fetchedRows() {
58
+ return this._fetchedRows;
59
+ }
60
+ /**
61
+ * Returns object instance which contains information about fields.
62
+ */
63
+ get fields() {
64
+ return this._fields;
65
+ }
66
+ /**
67
+ * Returns current row
68
+ */
69
+ get row() {
70
+ return this._row;
71
+ }
72
+ /**
73
+ * Returns current row number.
74
+ */
75
+ get rowNum() {
76
+ return this._rowNum;
77
+ }
78
+ /**
79
+ * Enables cache
80
+ */
81
+ cached() {
82
+ if (this.fetchedRows)
83
+ throw new Error('Cache can be enabled before fetching rows');
84
+ if (!this._cache)
85
+ this._cache = new DoublyLinked();
86
+ }
87
+ /**
88
+ * Closes cursor
89
+ */
90
+ async close() {
91
+ if (!this._intlcur)
92
+ return;
93
+ try {
94
+ await this._intlcur.close();
95
+ this._intlcur = undefined;
96
+ debug('close');
97
+ this.emit('close');
98
+ }
99
+ catch (err) {
100
+ debug('close-error:', err);
101
+ this.emit('error', err);
102
+ throw err;
103
+ }
104
+ }
105
+ /**
106
+ * If cache is enabled, this call fetches and keeps all records in the internal cache.
107
+ * Otherwise it throws error. Once all all records fetched,
108
+ * you can close Cursor safely and can continue to use it in memory.
109
+ * Returns number of fetched rows
110
+ */
111
+ async fetchAll() {
112
+ if (!this._cache)
113
+ throw new Error('fetchAll() method needs cache to be enabled');
114
+ const n = this.rowNum;
115
+ const v = await this._seek(Number.MAX_SAFE_INTEGER, true);
116
+ await this._seek(n - this.rowNum, true);
117
+ return v;
118
+ }
119
+ /**
120
+ * Moves cursor to given row number.
121
+ * cursor can move both forward and backward if cache enabled.
122
+ * Otherwise it throws error.
123
+ */
124
+ async moveTo(rowNum) {
125
+ await this._seek(rowNum - this.rowNum);
126
+ return this.row;
127
+ }
128
+ /**
129
+ * Moves cursor forward by one row and returns that row.
130
+ * And also it allows iterating over rows easily.
131
+ */
132
+ async next() {
133
+ debug('next');
134
+ await this._seek(1);
135
+ return this.row;
136
+ }
137
+ /**
138
+ * Moves cursor back by one row and returns that row.
139
+ * And also it allows iterating over rows easily.
140
+ */
141
+ async prev() {
142
+ await this._seek(-1);
143
+ return this.row;
144
+ }
145
+ /**
146
+ * Moves cursor before first row. (Required cache enabled)
147
+ */
148
+ reset() {
149
+ if (!this._cache)
150
+ throw new Error('reset() method needs cache to be enabled');
151
+ this._cache.reset();
152
+ this._rowNum = 0;
153
+ this.emit('reset');
154
+ }
155
+ /**
156
+ * Moves cursor by given step. If caching is enabled,
157
+ * cursor can move both forward and backward. Otherwise it throws error.
158
+ */
159
+ async seek(step) {
160
+ await this._seek(step);
161
+ return this.row;
162
+ }
163
+ /**
164
+ * Creates and returns a readable stream.
165
+ */
166
+ toStream(options) {
167
+ return new CursorStream(this, options);
168
+ }
169
+ toString() {
170
+ return '[object ' + Object.getPrototypeOf(this).constructor.name + ']';
171
+ }
172
+ inspect() {
173
+ return this.toString();
174
+ }
175
+ /**
176
+ *
177
+ */
178
+ async _seek(step, silent) {
179
+ step = coerceToInt(step, 0);
180
+ if (!step || (step > 0 && this.isClosed))
181
+ return this.rowNum;
182
+ if (step < 0 && !this._cache)
183
+ throw new Error('To move cursor back, it needs cache to be enabled');
184
+ const _this = this;
185
+ await this._taskQueue.enqueue(async function () {
186
+ /* If moving backward */
187
+ if (step < 0) {
188
+ /* Seek cache */
189
+ while (step < 0 && _this._cache?.cursor) {
190
+ _this._row = _this._cache.prev();
191
+ _this._rowNum--;
192
+ step++;
193
+ }
194
+ return;
195
+ }
196
+ while (step > 0) {
197
+ if (_this.isEof)
198
+ return;
199
+ /* Seek cache */
200
+ while (step > 0 && _this._cache && (_this._row = _this._cache.next())) {
201
+ _this._rowNum++;
202
+ step--;
203
+ }
204
+ /* Fetch from prefetch cache */
205
+ while (step > 0 && (_this._row = _this._fetchCache.shift())) {
206
+ _this._rowNum++;
207
+ step--;
208
+ }
209
+ if (_this._fetchedAll) {
210
+ _this._rowNum++;
211
+ _this.emit('eof');
212
+ return;
213
+ }
214
+ if (!step || _this._fetchedAll)
215
+ return;
216
+ await _this._fetchRows();
217
+ }
218
+ });
219
+ if (!silent)
220
+ this.emit('move', this.row, this._rowNum);
221
+ return this._rowNum;
222
+ }
223
+ /**
224
+ *
225
+ */
226
+ async _fetchRows() {
227
+ if (!this._intlcur)
228
+ throw new Error('Cursor is closed');
229
+ let rows = await this._intlcur.fetch(this._prefetchRows);
230
+ if (rows && rows.length) {
231
+ debug('Fetched %d rows from database', rows.length);
232
+ // Normalize rows
233
+ rows = this._request.objectRows ?
234
+ normalizeRowsToObjectRows(this._fields, this._intlcur.rowType, rows, this._request) :
235
+ normalizeRowsToArrayRows(this._fields, this._intlcur.rowType, rows, this._request);
236
+ callFetchHooks(rows, this._request);
237
+ for (const [idx, row] of rows.entries()) {
238
+ this.emit('fetch', row, (this._rowNum + idx + 1));
239
+ }
240
+ /* Add rows to cache */
241
+ if (this._cache) {
242
+ this._cache.push(...rows);
243
+ }
244
+ else
245
+ this._fetchCache.push(...rows);
246
+ this._fetchedRows += rows.length;
247
+ return;
248
+ }
249
+ this._fetchedAll = true;
250
+ return this.close();
251
+ }
252
+ }
@@ -1,4 +1,4 @@
1
- import { Adapter } from './Adapter';
1
+ import { Adapter } from './adapter.js';
2
2
  export declare let adapters: Adapter[];
3
3
  export declare function registerAdapter(adapter: Adapter): void;
4
4
  export declare function unRegisterAdapter(...adapter: Adapter[]): void;
@@ -0,0 +1,9 @@
1
+ export let adapters = [];
2
+ export function registerAdapter(adapter) {
3
+ if (!adapter.driver)
4
+ throw new TypeError('A DatabaseAdapter must contain "driver" property');
5
+ adapters.push(adapter);
6
+ }
7
+ export function unRegisterAdapter(...adapter) {
8
+ adapters = adapters.filter(x => !adapter.includes(x));
9
+ }
@@ -1,4 +1,4 @@
1
- import { FieldInfo } from './types';
1
+ import { FieldInfo } from './types.js';
2
2
  export declare class FieldInfoMap {
3
3
  private _obj;
4
4
  private _arr;
@@ -0,0 +1,50 @@
1
+ export class FieldInfoMap {
2
+ _obj;
3
+ _arr;
4
+ constructor() {
5
+ Object.defineProperty(this, '_obj', {
6
+ enumerable: false,
7
+ configurable: false,
8
+ writable: true,
9
+ value: {}
10
+ });
11
+ Object.defineProperty(this, '_arr', {
12
+ enumerable: false,
13
+ configurable: false,
14
+ writable: true,
15
+ value: []
16
+ });
17
+ }
18
+ add(field) {
19
+ const idx = field.index != null ? field.index : this._arr.length;
20
+ this._arr[idx] = field;
21
+ field.index = idx;
22
+ const _obj = this._arr.reduce((a, f) => {
23
+ a[f.name.toUpperCase()] = f;
24
+ return a;
25
+ }, {});
26
+ Object.defineProperty(this, '_obj', {
27
+ enumerable: false,
28
+ configurable: false,
29
+ writable: true,
30
+ value: _obj
31
+ });
32
+ }
33
+ get(k) {
34
+ if (typeof k === 'number')
35
+ return this._arr[k];
36
+ return this._obj[k.toUpperCase()];
37
+ }
38
+ entries() {
39
+ return Object.entries(this._obj);
40
+ }
41
+ keys() {
42
+ return Object.keys(this._obj);
43
+ }
44
+ values() {
45
+ return [...this._arr];
46
+ }
47
+ toJSON() {
48
+ return { ...this._obj };
49
+ }
50
+ }
@@ -1,7 +1,7 @@
1
1
  import { Maybe } from 'ts-gems';
2
- import { Adapter } from './Adapter';
3
- import { FieldInfoMap } from './FieldInfoMap';
4
- import { ArrayRowset, FieldNaming, ObjectRowset, QueryRequest } from './types';
2
+ import { Adapter } from './adapter.js';
3
+ import { FieldInfoMap } from './field-info-map.js';
4
+ import { ArrayRowset, FieldNaming, ObjectRowset, QueryRequest } from './types.js';
5
5
  export declare function applyNamingStrategy(value: string, namingStrategy?: FieldNaming): Maybe<string>;
6
6
  export declare function wrapAdapterFields(oldFields: Adapter.Field[], fieldNaming?: FieldNaming): FieldInfoMap;
7
7
  export declare function normalizeRowsToObjectRows(fields: FieldInfoMap, rowType: 'array' | 'object', oldRows: ObjectRowset | ArrayRowset, options?: Pick<QueryRequest, 'ignoreNulls' | 'transform'>): Record<string, any>[];
@@ -0,0 +1,125 @@
1
+ import { camelCase, pascalCase } from "putil-varhelpers";
2
+ import { FieldInfoMap } from './field-info-map.js';
3
+ export function applyNamingStrategy(value, namingStrategy) {
4
+ if (typeof namingStrategy === 'string' && namingStrategy !== 'original') {
5
+ switch (namingStrategy.toLowerCase()) {
6
+ case 'lowercase':
7
+ return value.toLowerCase();
8
+ case 'uppercase':
9
+ return value.toUpperCase();
10
+ case 'camelcase':
11
+ if (!value.match(/[a-z]/))
12
+ return camelCase(value.toLowerCase());
13
+ value = camelCase(value);
14
+ return value[0].toLowerCase() + value.substring(1);
15
+ case 'pascalcase':
16
+ if (!value.match(/[a-z]/))
17
+ return pascalCase(value.toLowerCase());
18
+ return pascalCase(value);
19
+ }
20
+ }
21
+ else if (typeof namingStrategy === 'function')
22
+ return namingStrategy(value);
23
+ return value;
24
+ }
25
+ export function wrapAdapterFields(oldFields, fieldNaming) {
26
+ const mapFieldInfo = (f, index) => {
27
+ const name = applyNamingStrategy(f.fieldName, fieldNaming);
28
+ if (name)
29
+ return { ...f, name, index };
30
+ };
31
+ const result = new FieldInfoMap();
32
+ let i = 0;
33
+ oldFields.forEach(f => {
34
+ const x = mapFieldInfo(f, i);
35
+ if (x) {
36
+ i++;
37
+ result.add(x);
38
+ }
39
+ });
40
+ return result;
41
+ }
42
+ export function normalizeRowsToObjectRows(fields, rowType, oldRows, options) {
43
+ return normalizeRows(fields, rowType, oldRows, { ...options, objectRows: true });
44
+ }
45
+ export function normalizeRowsToArrayRows(fields, rowType, oldRows, options) {
46
+ return normalizeRows(fields, rowType, oldRows, { ...options, objectRows: false });
47
+ }
48
+ function normalizeRows(fields, rowType, oldRows, options) {
49
+ const ignoreNulls = options.ignoreNulls && options.objectRows;
50
+ const transform = options.transform;
51
+ const coerceValue = (v, f) => {
52
+ if (v === undefined)
53
+ return;
54
+ if (transform)
55
+ v = transform(v, f);
56
+ if (v === null && ignoreNulls)
57
+ return;
58
+ return v;
59
+ };
60
+ if (options.objectRows) {
61
+ if (rowType === 'array') {
62
+ return oldRows.map((row) => {
63
+ const r = {};
64
+ for (const f of fields.values()) {
65
+ const v = coerceValue(row[f.index], f);
66
+ if (v !== undefined)
67
+ r[f.name] = v;
68
+ }
69
+ return r;
70
+ });
71
+ }
72
+ let hasFieldNaming = false;
73
+ for (const f of fields.values()) {
74
+ if (f.name !== f.fieldName) {
75
+ hasFieldNaming = true;
76
+ break;
77
+ }
78
+ }
79
+ if (hasFieldNaming || transform) {
80
+ return oldRows.map((row) => {
81
+ const r = {};
82
+ for (const f of fields.values()) {
83
+ const v = coerceValue(row[f.fieldName], f);
84
+ if (v !== undefined)
85
+ r[f.name] = v;
86
+ }
87
+ return r;
88
+ });
89
+ }
90
+ if (ignoreNulls) {
91
+ oldRows.forEach(row => {
92
+ for (const [k, v] of Object.entries(row)) {
93
+ if (v === null)
94
+ delete row[k];
95
+ }
96
+ });
97
+ }
98
+ return oldRows;
99
+ }
100
+ if (rowType === 'array') {
101
+ oldRows.forEach((row) => {
102
+ for (const [i, v] of row.entries()) {
103
+ row[i] = coerceValue(v, fields.get(i));
104
+ }
105
+ });
106
+ return oldRows;
107
+ }
108
+ return oldRows.map((row) => {
109
+ const r = [];
110
+ for (const f of fields.values()) {
111
+ r[f.index] = coerceValue(row[f.fieldName], f);
112
+ }
113
+ return r;
114
+ });
115
+ }
116
+ export function callFetchHooks(rows, request) {
117
+ const fetchHooks = request.fetchHooks;
118
+ if (!fetchHooks)
119
+ return;
120
+ for (const row of rows) {
121
+ for (const fn of fetchHooks) {
122
+ fn(row, request);
123
+ }
124
+ }
125
+ }
@@ -1,9 +1,9 @@
1
1
  import { Pool as LightningPool } from 'lightning-pool';
2
2
  import { Maybe, Type } from 'ts-gems';
3
3
  import { classes } from '@sqb/builder';
4
- import { Repository } from '../orm/repository.class';
5
- import { SqbConnection } from './SqbConnection';
6
- import { ArrayQueryResult, ClientConfiguration, ClientDefaults, ConnectionOptions, ObjectQueryResult, QueryExecuteOptions, QueryRequest, TransactionFunction } from './types';
4
+ import { Repository } from '../orm/repository.class.js';
5
+ import { SqbConnection } from './sqb-connection.js';
6
+ import { ClientConfiguration, ClientDefaults, ConnectionOptions, QueryExecuteOptions, QueryRequest, QueryResult, TransactionFunction } from './types.js';
7
7
  declare const inspect: unique symbol;
8
8
  interface SqbClientEvents {
9
9
  execute: (request: QueryRequest) => void;
@@ -49,13 +49,7 @@ export declare class SqbClient extends SqbClient_base {
49
49
  /**
50
50
  * Executes a query or callback with a new acquired connection.
51
51
  */
52
- execute(query: string | classes.Query, options?: QueryExecuteOptions & {
53
- objectRows: true;
54
- }): Promise<ObjectQueryResult>;
55
- execute(query: string | classes.Query, options?: QueryExecuteOptions & {
56
- objectRows: false;
57
- }): Promise<ArrayQueryResult>;
58
- execute(query: string | classes.Query, options?: QueryExecuteOptions): Promise<ObjectQueryResult | ArrayQueryResult>;
52
+ execute(query: string | classes.Query, options?: QueryExecuteOptions): Promise<QueryResult>;
59
53
  /**
60
54
  * Tests the pool
61
55
  */