rayforce-wasm 0.1.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/LICENSE +21 -0
- package/README.md +305 -0
- package/dist/index.js +215 -0
- package/dist/rayforce.js +16 -0
- package/dist/rayforce.sdk.d.ts +493 -0
- package/dist/rayforce.sdk.js +1591 -0
- package/dist/rayforce.umd.js +933 -0
- package/dist/rayforce.wasm +0 -0
- package/package.json +48 -0
|
@@ -0,0 +1,1591 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RayforceDB JavaScript SDK
|
|
3
|
+
*
|
|
4
|
+
* Full-featured zero-copy wrapper for RayforceDB WASM module.
|
|
5
|
+
* Provides TypedArray views over native Rayforce vectors for efficient data access.
|
|
6
|
+
*
|
|
7
|
+
* @module rayforce
|
|
8
|
+
* @version 0.1.0
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// SDK Factory
|
|
13
|
+
// ============================================================================
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new RayforceDB SDK instance.
|
|
17
|
+
* @param {Object} wasmModule - The initialized Emscripten WASM module
|
|
18
|
+
* @returns {RayforceSDK} The SDK instance
|
|
19
|
+
*/
|
|
20
|
+
export function createRayforceSDK(wasmModule) {
|
|
21
|
+
return new RayforceSDK(wasmModule);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Type Constants
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
export const Types = Object.freeze({
|
|
29
|
+
LIST: 0,
|
|
30
|
+
B8: 1,
|
|
31
|
+
U8: 2,
|
|
32
|
+
I16: 3,
|
|
33
|
+
I32: 4,
|
|
34
|
+
I64: 5,
|
|
35
|
+
SYMBOL: 6,
|
|
36
|
+
DATE: 7,
|
|
37
|
+
TIME: 8,
|
|
38
|
+
TIMESTAMP: 9,
|
|
39
|
+
F64: 10,
|
|
40
|
+
GUID: 11,
|
|
41
|
+
C8: 12,
|
|
42
|
+
TABLE: 98,
|
|
43
|
+
DICT: 99,
|
|
44
|
+
LAMBDA: 100,
|
|
45
|
+
NULL: 126,
|
|
46
|
+
ERR: 127,
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Element sizes for each type (in bytes)
|
|
50
|
+
const ELEMENT_SIZES = {
|
|
51
|
+
[Types.B8]: 1,
|
|
52
|
+
[Types.U8]: 1,
|
|
53
|
+
[Types.C8]: 1,
|
|
54
|
+
[Types.I16]: 2,
|
|
55
|
+
[Types.I32]: 4,
|
|
56
|
+
[Types.I64]: 8,
|
|
57
|
+
[Types.F64]: 8,
|
|
58
|
+
[Types.DATE]: 4,
|
|
59
|
+
[Types.TIME]: 4,
|
|
60
|
+
[Types.TIMESTAMP]: 8,
|
|
61
|
+
[Types.SYMBOL]: 8,
|
|
62
|
+
[Types.GUID]: 16,
|
|
63
|
+
[Types.LIST]: 4, // pointer size in WASM32
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// TypedArray constructors for each type
|
|
67
|
+
const TYPED_ARRAY_MAP = {
|
|
68
|
+
[Types.B8]: Int8Array,
|
|
69
|
+
[Types.U8]: Uint8Array,
|
|
70
|
+
[Types.C8]: Uint8Array,
|
|
71
|
+
[Types.I16]: Int16Array,
|
|
72
|
+
[Types.I32]: Int32Array,
|
|
73
|
+
[Types.I64]: BigInt64Array,
|
|
74
|
+
[Types.F64]: Float64Array,
|
|
75
|
+
[Types.DATE]: Int32Array,
|
|
76
|
+
[Types.TIME]: Int32Array,
|
|
77
|
+
[Types.TIMESTAMP]: BigInt64Array,
|
|
78
|
+
[Types.SYMBOL]: BigInt64Array,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
// ============================================================================
|
|
82
|
+
// Main SDK Class
|
|
83
|
+
// ============================================================================
|
|
84
|
+
|
|
85
|
+
class RayforceSDK {
|
|
86
|
+
constructor(wasm) {
|
|
87
|
+
this._wasm = wasm;
|
|
88
|
+
this._cmdCounter = 0;
|
|
89
|
+
this._setupBindings();
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
_setupBindings() {
|
|
93
|
+
const w = this._wasm;
|
|
94
|
+
|
|
95
|
+
// Core functions
|
|
96
|
+
this._evalCmd = w.cwrap('eval_cmd', 'number', ['string', 'string']);
|
|
97
|
+
this._evalStr = w.cwrap('eval_str', 'number', ['string']);
|
|
98
|
+
this._strOfObj = w.cwrap('strof_obj', 'string', ['number']);
|
|
99
|
+
this._dropObj = w.cwrap('drop_obj', null, ['number']);
|
|
100
|
+
this._cloneObj = w.cwrap('clone_obj', 'number', ['number']);
|
|
101
|
+
this._versionStr = w.cwrap('version_str', 'string', []);
|
|
102
|
+
|
|
103
|
+
// Type introspection
|
|
104
|
+
this._getObjType = w.cwrap('get_obj_type', 'number', ['number']);
|
|
105
|
+
this._getObjLen = w.cwrap('get_obj_len', 'number', ['number']);
|
|
106
|
+
this._isObjAtom = w.cwrap('is_obj_atom', 'number', ['number']);
|
|
107
|
+
this._isObjVector = w.cwrap('is_obj_vector', 'number', ['number']);
|
|
108
|
+
this._isObjNull = w.cwrap('is_obj_null', 'number', ['number']);
|
|
109
|
+
this._isObjError = w.cwrap('is_obj_error', 'number', ['number']);
|
|
110
|
+
this._getObjRc = w.cwrap('get_obj_rc', 'number', ['number']);
|
|
111
|
+
|
|
112
|
+
// Memory access
|
|
113
|
+
this._getDataPtr = w.cwrap('get_data_ptr', 'number', ['number']);
|
|
114
|
+
this._getElementSize = w.cwrap('get_element_size', 'number', ['number']);
|
|
115
|
+
this._getDataByteSize = w.cwrap('get_data_byte_size', 'number', ['number']);
|
|
116
|
+
|
|
117
|
+
// Scalar constructors
|
|
118
|
+
this._initB8 = w.cwrap('init_b8', 'number', ['number']);
|
|
119
|
+
this._initU8 = w.cwrap('init_u8', 'number', ['number']);
|
|
120
|
+
this._initC8 = w.cwrap('init_c8', 'number', ['number']);
|
|
121
|
+
this._initI16 = w.cwrap('init_i16', 'number', ['number']);
|
|
122
|
+
this._initI32 = w.cwrap('init_i32', 'number', ['number']);
|
|
123
|
+
this._initI64 = w.cwrap('init_i64', 'number', ['number']);
|
|
124
|
+
this._initF64 = w.cwrap('init_f64', 'number', ['number']);
|
|
125
|
+
this._initDate = w.cwrap('init_date', 'number', ['number']);
|
|
126
|
+
this._initTime = w.cwrap('init_time', 'number', ['number']);
|
|
127
|
+
this._initTimestamp = w.cwrap('init_timestamp', 'number', ['number']);
|
|
128
|
+
this._initSymbolStr = w.cwrap('init_symbol_str', 'number', ['string', 'number']);
|
|
129
|
+
this._initStringStr = w.cwrap('init_string_str', 'number', ['string', 'number']);
|
|
130
|
+
|
|
131
|
+
// Scalar readers
|
|
132
|
+
this._readB8 = w.cwrap('read_b8', 'number', ['number']);
|
|
133
|
+
this._readU8 = w.cwrap('read_u8', 'number', ['number']);
|
|
134
|
+
this._readC8 = w.cwrap('read_c8', 'number', ['number']);
|
|
135
|
+
this._readI16 = w.cwrap('read_i16', 'number', ['number']);
|
|
136
|
+
this._readI32 = w.cwrap('read_i32', 'number', ['number']);
|
|
137
|
+
this._readI64 = w.cwrap('read_i64', 'number', ['number']);
|
|
138
|
+
this._readF64 = w.cwrap('read_f64', 'number', ['number']);
|
|
139
|
+
this._readDate = w.cwrap('read_date', 'number', ['number']);
|
|
140
|
+
this._readTime = w.cwrap('read_time', 'number', ['number']);
|
|
141
|
+
this._readTimestamp = w.cwrap('read_timestamp', 'number', ['number']);
|
|
142
|
+
this._readSymbolId = w.cwrap('read_symbol_id', 'number', ['number']);
|
|
143
|
+
this._symbolToStr = w.cwrap('symbol_to_str', 'string', ['number']);
|
|
144
|
+
|
|
145
|
+
// Vector operations
|
|
146
|
+
this._initVector = w.cwrap('init_vector', 'number', ['number', 'number']);
|
|
147
|
+
this._initList = w.cwrap('init_list', 'number', ['number']);
|
|
148
|
+
this._vecAtIdx = w.cwrap('vec_at_idx', 'number', ['number', 'number']);
|
|
149
|
+
this._atIdx = w.cwrap('at_idx', 'number', ['number', 'number']);
|
|
150
|
+
this._atObj = w.cwrap('at_obj', 'number', ['number', 'number']);
|
|
151
|
+
this._pushObj = w.cwrap('push_obj', 'number', ['number', 'number']);
|
|
152
|
+
this._insObj = w.cwrap('ins_obj', 'number', ['number', 'number', 'number']);
|
|
153
|
+
|
|
154
|
+
// Dict operations
|
|
155
|
+
this._initDict = w.cwrap('init_dict', 'number', ['number', 'number']);
|
|
156
|
+
this._dictKeys = w.cwrap('dict_keys', 'number', ['number']);
|
|
157
|
+
this._dictVals = w.cwrap('dict_vals', 'number', ['number']);
|
|
158
|
+
this._dictGet = w.cwrap('dict_get', 'number', ['number', 'number']);
|
|
159
|
+
|
|
160
|
+
// Table operations
|
|
161
|
+
this._initTable = w.cwrap('init_table', 'number', ['number', 'number']);
|
|
162
|
+
this._tableKeys = w.cwrap('table_keys', 'number', ['number']);
|
|
163
|
+
this._tableVals = w.cwrap('table_vals', 'number', ['number']);
|
|
164
|
+
this._tableCol = w.cwrap('table_col', 'number', ['number', 'string', 'number']);
|
|
165
|
+
this._tableRow = w.cwrap('table_row', 'number', ['number', 'number']);
|
|
166
|
+
this._tableCount = w.cwrap('table_count', 'number', ['number']);
|
|
167
|
+
|
|
168
|
+
// Query operations
|
|
169
|
+
this._querySelect = w.cwrap('query_select', 'number', ['number']);
|
|
170
|
+
this._queryUpdate = w.cwrap('query_update', 'number', ['number']);
|
|
171
|
+
this._tableInsert = w.cwrap('table_insert', 'number', ['number', 'number']);
|
|
172
|
+
this._tableUpsert = w.cwrap('table_upsert', 'number', ['number', 'number', 'number']);
|
|
173
|
+
|
|
174
|
+
// Other operations
|
|
175
|
+
this._internSymbol = w.cwrap('intern_symbol', 'number', ['string', 'number']);
|
|
176
|
+
this._globalSet = w.cwrap('global_set', null, ['number', 'number']);
|
|
177
|
+
this._quoteObj = w.cwrap('quote_obj', 'number', ['number']);
|
|
178
|
+
this._serialize = w.cwrap('serialize', 'number', ['number']);
|
|
179
|
+
this._deserialize = w.cwrap('deserialize', 'number', ['number']);
|
|
180
|
+
this._getTypeName = w.cwrap('get_type_name', 'string', ['number']);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ==========================================================================
|
|
184
|
+
// Core Methods
|
|
185
|
+
// ==========================================================================
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get RayforceDB version string
|
|
189
|
+
* @returns {string}
|
|
190
|
+
*/
|
|
191
|
+
get version() {
|
|
192
|
+
return this._versionStr();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Evaluate a Rayfall expression
|
|
197
|
+
* @param {string} code - The expression to evaluate
|
|
198
|
+
* @param {string} [sourceName] - Optional source name for error tracking
|
|
199
|
+
* @returns {RayObject} The result wrapped in appropriate type
|
|
200
|
+
*/
|
|
201
|
+
eval(code, sourceName) {
|
|
202
|
+
const ptr = this._evalCmd(code, sourceName || `eval:${++this._cmdCounter}`);
|
|
203
|
+
return this._wrapPtr(ptr);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Evaluate and return raw result (for internal use)
|
|
208
|
+
* @param {string} code
|
|
209
|
+
* @returns {number} Raw pointer
|
|
210
|
+
*/
|
|
211
|
+
_evalRaw(code) {
|
|
212
|
+
return this._evalCmd(code, `eval:${++this._cmdCounter}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Format any RayObject to string
|
|
217
|
+
* @param {RayObject|number} obj
|
|
218
|
+
* @returns {string}
|
|
219
|
+
*/
|
|
220
|
+
format(obj) {
|
|
221
|
+
const ptr = obj instanceof RayObject ? obj._ptr : obj;
|
|
222
|
+
return this._strOfObj(ptr);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ==========================================================================
|
|
226
|
+
// Type Wrapping
|
|
227
|
+
// ==========================================================================
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Wrap a raw pointer in the appropriate RayObject subclass
|
|
231
|
+
* @param {number} ptr
|
|
232
|
+
* @returns {RayObject}
|
|
233
|
+
*/
|
|
234
|
+
_wrapPtr(ptr) {
|
|
235
|
+
if (ptr === 0) return new RayNull(this, 0);
|
|
236
|
+
|
|
237
|
+
const type = this._getObjType(ptr);
|
|
238
|
+
const isAtom = this._isObjAtom(ptr);
|
|
239
|
+
const absType = type < 0 ? -type : type;
|
|
240
|
+
|
|
241
|
+
// Check for error
|
|
242
|
+
if (type === Types.ERR) {
|
|
243
|
+
return new RayError(this, ptr);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Check for null
|
|
247
|
+
if (type === Types.NULL || this._isObjNull(ptr)) {
|
|
248
|
+
return new RayNull(this, ptr);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// Atoms (scalars)
|
|
252
|
+
if (isAtom) {
|
|
253
|
+
switch (absType) {
|
|
254
|
+
case Types.B8: return new B8(this, ptr);
|
|
255
|
+
case Types.U8: return new U8(this, ptr);
|
|
256
|
+
case Types.C8: return new C8(this, ptr);
|
|
257
|
+
case Types.I16: return new I16(this, ptr);
|
|
258
|
+
case Types.I32: return new I32(this, ptr);
|
|
259
|
+
case Types.I64: return new I64(this, ptr);
|
|
260
|
+
case Types.F64: return new F64(this, ptr);
|
|
261
|
+
case Types.DATE: return new RayDate(this, ptr);
|
|
262
|
+
case Types.TIME: return new RayTime(this, ptr);
|
|
263
|
+
case Types.TIMESTAMP: return new RayTimestamp(this, ptr);
|
|
264
|
+
case Types.SYMBOL: return new Symbol(this, ptr);
|
|
265
|
+
case Types.GUID: return new GUID(this, ptr);
|
|
266
|
+
default: return new RayObject(this, ptr);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// Vectors and containers
|
|
271
|
+
switch (type) {
|
|
272
|
+
case Types.C8: return new RayString(this, ptr);
|
|
273
|
+
case Types.LIST: return new List(this, ptr);
|
|
274
|
+
case Types.DICT: return new Dict(this, ptr);
|
|
275
|
+
case Types.TABLE: return new Table(this, ptr);
|
|
276
|
+
case Types.LAMBDA: return new Lambda(this, ptr);
|
|
277
|
+
default:
|
|
278
|
+
// Numeric vectors
|
|
279
|
+
if (TYPED_ARRAY_MAP[type]) {
|
|
280
|
+
return new Vector(this, ptr, type);
|
|
281
|
+
}
|
|
282
|
+
return new RayObject(this, ptr);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// ==========================================================================
|
|
287
|
+
// Constructors
|
|
288
|
+
// ==========================================================================
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Create a boolean value
|
|
292
|
+
* @param {boolean} value
|
|
293
|
+
* @returns {B8}
|
|
294
|
+
*/
|
|
295
|
+
b8(value) {
|
|
296
|
+
return new B8(this, this._initB8(value ? 1 : 0));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Create an unsigned byte value
|
|
301
|
+
* @param {number} value
|
|
302
|
+
* @returns {U8}
|
|
303
|
+
*/
|
|
304
|
+
u8(value) {
|
|
305
|
+
return new U8(this, this._initU8(value & 0xFF));
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Create a character value
|
|
310
|
+
* @param {string} value - Single character
|
|
311
|
+
* @returns {C8}
|
|
312
|
+
*/
|
|
313
|
+
c8(value) {
|
|
314
|
+
const code = value.charCodeAt(0);
|
|
315
|
+
return new C8(this, this._initC8(code));
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Create a 16-bit integer
|
|
320
|
+
* @param {number} value
|
|
321
|
+
* @returns {I16}
|
|
322
|
+
*/
|
|
323
|
+
i16(value) {
|
|
324
|
+
return new I16(this, this._initI16(value | 0));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Create a 32-bit integer
|
|
329
|
+
* @param {number} value
|
|
330
|
+
* @returns {I32}
|
|
331
|
+
*/
|
|
332
|
+
i32(value) {
|
|
333
|
+
return new I32(this, this._initI32(value | 0));
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Create a 64-bit integer
|
|
338
|
+
* @param {number|bigint} value
|
|
339
|
+
* @returns {I64}
|
|
340
|
+
*/
|
|
341
|
+
i64(value) {
|
|
342
|
+
// Note: JS number can only safely represent up to 2^53
|
|
343
|
+
return new I64(this, this._initI64(Number(value)));
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Create a 64-bit float
|
|
348
|
+
* @param {number} value
|
|
349
|
+
* @returns {F64}
|
|
350
|
+
*/
|
|
351
|
+
f64(value) {
|
|
352
|
+
return new F64(this, this._initF64(value));
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/**
|
|
356
|
+
* Create a date (days since 2000-01-01)
|
|
357
|
+
* @param {number|Date} value - Days or JS Date object
|
|
358
|
+
* @returns {RayDate}
|
|
359
|
+
*/
|
|
360
|
+
date(value) {
|
|
361
|
+
let days;
|
|
362
|
+
if (value instanceof Date) {
|
|
363
|
+
// Convert JS Date to days since 2000-01-01
|
|
364
|
+
const epoch = new Date(2000, 0, 1);
|
|
365
|
+
days = Math.floor((value - epoch) / (1000 * 60 * 60 * 24));
|
|
366
|
+
} else {
|
|
367
|
+
days = value | 0;
|
|
368
|
+
}
|
|
369
|
+
return new RayDate(this, this._initDate(days));
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Create a time (milliseconds since midnight)
|
|
374
|
+
* @param {number|Date} value - Milliseconds or JS Date object
|
|
375
|
+
* @returns {RayTime}
|
|
376
|
+
*/
|
|
377
|
+
time(value) {
|
|
378
|
+
let ms;
|
|
379
|
+
if (value instanceof Date) {
|
|
380
|
+
ms = value.getHours() * 3600000 +
|
|
381
|
+
value.getMinutes() * 60000 +
|
|
382
|
+
value.getSeconds() * 1000 +
|
|
383
|
+
value.getMilliseconds();
|
|
384
|
+
} else {
|
|
385
|
+
ms = value | 0;
|
|
386
|
+
}
|
|
387
|
+
return new RayTime(this, this._initTime(ms));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Create a timestamp (nanoseconds since 2000-01-01)
|
|
392
|
+
* @param {number|bigint|Date} value - Nanoseconds or JS Date
|
|
393
|
+
* @returns {RayTimestamp}
|
|
394
|
+
*/
|
|
395
|
+
timestamp(value) {
|
|
396
|
+
let ns;
|
|
397
|
+
if (value instanceof Date) {
|
|
398
|
+
const epoch = new Date(2000, 0, 1);
|
|
399
|
+
ns = Number(value - epoch) * 1000000; // ms to ns
|
|
400
|
+
} else {
|
|
401
|
+
ns = Number(value);
|
|
402
|
+
}
|
|
403
|
+
return new RayTimestamp(this, this._initTimestamp(ns));
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Create a symbol (interned string)
|
|
408
|
+
* @param {string} value
|
|
409
|
+
* @returns {Symbol}
|
|
410
|
+
*/
|
|
411
|
+
symbol(value) {
|
|
412
|
+
return new Symbol(this, this._initSymbolStr(value, value.length));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Create a string
|
|
417
|
+
* @param {string} value
|
|
418
|
+
* @returns {RayString}
|
|
419
|
+
*/
|
|
420
|
+
string(value) {
|
|
421
|
+
return new RayString(this, this._initStringStr(value, value.length));
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Create a vector of specified type
|
|
426
|
+
* @param {number} type - Type code from Types
|
|
427
|
+
* @param {number|Array} lengthOrData - Length or array of values
|
|
428
|
+
* @returns {Vector}
|
|
429
|
+
*/
|
|
430
|
+
vector(type, lengthOrData) {
|
|
431
|
+
if (Array.isArray(lengthOrData)) {
|
|
432
|
+
const arr = lengthOrData;
|
|
433
|
+
const vec = new Vector(this, this._initVector(type, arr.length), type);
|
|
434
|
+
const view = vec.typedArray;
|
|
435
|
+
for (let i = 0; i < arr.length; i++) {
|
|
436
|
+
if (type === Types.I64 || type === Types.TIMESTAMP || type === Types.SYMBOL) {
|
|
437
|
+
view[i] = BigInt(arr[i]);
|
|
438
|
+
} else {
|
|
439
|
+
view[i] = arr[i];
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return vec;
|
|
443
|
+
}
|
|
444
|
+
return new Vector(this, this._initVector(type, lengthOrData), type);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Create a list (mixed-type container)
|
|
449
|
+
* @param {Array} [items] - Optional array of items
|
|
450
|
+
* @returns {List}
|
|
451
|
+
*/
|
|
452
|
+
list(items) {
|
|
453
|
+
const len = items ? items.length : 0;
|
|
454
|
+
const list = new List(this, this._initList(len));
|
|
455
|
+
if (items) {
|
|
456
|
+
for (let i = 0; i < items.length; i++) {
|
|
457
|
+
list.set(i, items[i]);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
return list;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Create a dict (key-value mapping)
|
|
465
|
+
* @param {Object} obj - JS object to convert
|
|
466
|
+
* @returns {Dict}
|
|
467
|
+
*/
|
|
468
|
+
dict(obj) {
|
|
469
|
+
const keys = Object.keys(obj);
|
|
470
|
+
const keyVec = this.vector(Types.SYMBOL, keys.length);
|
|
471
|
+
const keyView = keyVec.typedArray;
|
|
472
|
+
for (let i = 0; i < keys.length; i++) {
|
|
473
|
+
keyView[i] = BigInt(this._internSymbol(keys[i], keys[i].length));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
const valList = this.list(Object.values(obj).map(v => this._toRayObject(v)));
|
|
477
|
+
return new Dict(this, this._initDict(keyVec._ptr, valList._ptr));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Create a table from column definitions
|
|
482
|
+
* @param {Object} columns - Object with column names as keys and arrays as values
|
|
483
|
+
* @returns {Table}
|
|
484
|
+
*/
|
|
485
|
+
table(columns) {
|
|
486
|
+
const colNames = Object.keys(columns);
|
|
487
|
+
const keyVec = this.vector(Types.SYMBOL, colNames.length);
|
|
488
|
+
const keyView = keyVec.typedArray;
|
|
489
|
+
for (let i = 0; i < colNames.length; i++) {
|
|
490
|
+
keyView[i] = BigInt(this._internSymbol(colNames[i], colNames[i].length));
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const valList = this.list();
|
|
494
|
+
for (const name of colNames) {
|
|
495
|
+
const data = columns[name];
|
|
496
|
+
const col = this._arrayToVector(data);
|
|
497
|
+
valList.push(col);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return new Table(this, this._initTable(keyVec._ptr, valList._ptr));
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Convert JS array to appropriate vector type
|
|
505
|
+
* @param {Array} arr
|
|
506
|
+
* @returns {Vector}
|
|
507
|
+
*/
|
|
508
|
+
_arrayToVector(arr) {
|
|
509
|
+
if (arr.length === 0) {
|
|
510
|
+
return this.vector(Types.I64, 0);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const first = arr[0];
|
|
514
|
+
let type;
|
|
515
|
+
|
|
516
|
+
if (typeof first === 'boolean') {
|
|
517
|
+
type = Types.B8;
|
|
518
|
+
} else if (typeof first === 'number') {
|
|
519
|
+
type = Number.isInteger(first) ? Types.I64 : Types.F64;
|
|
520
|
+
} else if (typeof first === 'bigint') {
|
|
521
|
+
type = Types.I64;
|
|
522
|
+
} else if (typeof first === 'string') {
|
|
523
|
+
type = Types.SYMBOL;
|
|
524
|
+
} else if (first instanceof Date) {
|
|
525
|
+
type = Types.TIMESTAMP;
|
|
526
|
+
} else {
|
|
527
|
+
// Default to list for mixed types
|
|
528
|
+
return this.list(arr.map(v => this._toRayObject(v)));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const vec = this.vector(type, arr.length);
|
|
532
|
+
const view = vec.typedArray;
|
|
533
|
+
|
|
534
|
+
for (let i = 0; i < arr.length; i++) {
|
|
535
|
+
if (type === Types.SYMBOL) {
|
|
536
|
+
view[i] = BigInt(this._internSymbol(arr[i], arr[i].length));
|
|
537
|
+
} else if (type === Types.I64 || type === Types.TIMESTAMP) {
|
|
538
|
+
if (arr[i] instanceof Date) {
|
|
539
|
+
const epoch = new Date(2000, 0, 1);
|
|
540
|
+
view[i] = BigInt((arr[i] - epoch) * 1000000);
|
|
541
|
+
} else {
|
|
542
|
+
view[i] = BigInt(arr[i]);
|
|
543
|
+
}
|
|
544
|
+
} else if (type === Types.B8) {
|
|
545
|
+
view[i] = arr[i] ? 1 : 0;
|
|
546
|
+
} else {
|
|
547
|
+
view[i] = arr[i];
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
return vec;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/**
|
|
555
|
+
* Convert JS value to RayObject
|
|
556
|
+
* @param {any} value
|
|
557
|
+
* @returns {RayObject}
|
|
558
|
+
*/
|
|
559
|
+
_toRayObject(value) {
|
|
560
|
+
if (value instanceof RayObject) return value;
|
|
561
|
+
if (value === null || value === undefined) return new RayNull(this, 0);
|
|
562
|
+
if (typeof value === 'boolean') return this.b8(value);
|
|
563
|
+
if (typeof value === 'number') {
|
|
564
|
+
return Number.isInteger(value) ? this.i64(value) : this.f64(value);
|
|
565
|
+
}
|
|
566
|
+
if (typeof value === 'bigint') return this.i64(value);
|
|
567
|
+
if (typeof value === 'string') return this.symbol(value);
|
|
568
|
+
if (value instanceof Date) return this.timestamp(value);
|
|
569
|
+
if (Array.isArray(value)) return this._arrayToVector(value);
|
|
570
|
+
if (typeof value === 'object') return this.dict(value);
|
|
571
|
+
return new RayNull(this, 0);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// ==========================================================================
|
|
575
|
+
// Utility Methods
|
|
576
|
+
// ==========================================================================
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Set a global variable
|
|
580
|
+
* @param {string} name
|
|
581
|
+
* @param {RayObject|any} value
|
|
582
|
+
*/
|
|
583
|
+
set(name, value) {
|
|
584
|
+
const sym = this.symbol(name);
|
|
585
|
+
const val = value instanceof RayObject ? value : this._toRayObject(value);
|
|
586
|
+
this._globalSet(sym._ptr, val._ptr);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
/**
|
|
590
|
+
* Get a global variable
|
|
591
|
+
* @param {string} name
|
|
592
|
+
* @returns {RayObject}
|
|
593
|
+
*/
|
|
594
|
+
get(name) {
|
|
595
|
+
return this.eval(name);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Get type name string
|
|
600
|
+
* @param {number} typeCode
|
|
601
|
+
* @returns {string}
|
|
602
|
+
*/
|
|
603
|
+
typeName(typeCode) {
|
|
604
|
+
return this._getTypeName(typeCode);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// ============================================================================
|
|
609
|
+
// Base RayObject Class
|
|
610
|
+
// ============================================================================
|
|
611
|
+
|
|
612
|
+
class RayObject {
|
|
613
|
+
constructor(sdk, ptr) {
|
|
614
|
+
this._sdk = sdk;
|
|
615
|
+
this._ptr = ptr;
|
|
616
|
+
this._owned = true;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Get raw pointer value
|
|
621
|
+
* @returns {number}
|
|
622
|
+
*/
|
|
623
|
+
get ptr() {
|
|
624
|
+
return this._ptr;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Get type code
|
|
629
|
+
* @returns {number}
|
|
630
|
+
*/
|
|
631
|
+
get type() {
|
|
632
|
+
return this._sdk._getObjType(this._ptr);
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
/**
|
|
636
|
+
* Get absolute type code (without sign)
|
|
637
|
+
* @returns {number}
|
|
638
|
+
*/
|
|
639
|
+
get absType() {
|
|
640
|
+
const t = this.type;
|
|
641
|
+
return t < 0 ? -t : t;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Check if this is an atom (scalar)
|
|
646
|
+
* @returns {boolean}
|
|
647
|
+
*/
|
|
648
|
+
get isAtom() {
|
|
649
|
+
return this._sdk._isObjAtom(this._ptr) !== 0;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* Check if this is a vector
|
|
654
|
+
* @returns {boolean}
|
|
655
|
+
*/
|
|
656
|
+
get isVector() {
|
|
657
|
+
return this._sdk._isObjVector(this._ptr) !== 0;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* Check if this is null
|
|
662
|
+
* @returns {boolean}
|
|
663
|
+
*/
|
|
664
|
+
get isNull() {
|
|
665
|
+
return this._sdk._isObjNull(this._ptr) !== 0;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Check if this is an error
|
|
670
|
+
* @returns {boolean}
|
|
671
|
+
*/
|
|
672
|
+
get isError() {
|
|
673
|
+
return this._sdk._isObjError(this._ptr) !== 0;
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Get length (1 for atoms)
|
|
678
|
+
* @returns {number}
|
|
679
|
+
*/
|
|
680
|
+
get length() {
|
|
681
|
+
return this._sdk._getObjLen(this._ptr);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Get reference count
|
|
686
|
+
* @returns {number}
|
|
687
|
+
*/
|
|
688
|
+
get refCount() {
|
|
689
|
+
return this._sdk._getObjRc(this._ptr);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* Clone this object
|
|
694
|
+
* @returns {RayObject}
|
|
695
|
+
*/
|
|
696
|
+
clone() {
|
|
697
|
+
return this._sdk._wrapPtr(this._sdk._cloneObj(this._ptr));
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
/**
|
|
701
|
+
* Format to string
|
|
702
|
+
* @returns {string}
|
|
703
|
+
*/
|
|
704
|
+
toString() {
|
|
705
|
+
return this._sdk.format(this._ptr);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* Convert to JavaScript value
|
|
710
|
+
* @returns {any}
|
|
711
|
+
*/
|
|
712
|
+
toJS() {
|
|
713
|
+
return this.toString();
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Free this object's memory
|
|
718
|
+
*/
|
|
719
|
+
drop() {
|
|
720
|
+
if (this._owned && this._ptr !== 0) {
|
|
721
|
+
this._sdk._dropObj(this._ptr);
|
|
722
|
+
this._ptr = 0;
|
|
723
|
+
this._owned = false;
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Release ownership (don't drop on GC)
|
|
729
|
+
* @returns {number} The raw pointer
|
|
730
|
+
*/
|
|
731
|
+
release() {
|
|
732
|
+
this._owned = false;
|
|
733
|
+
return this._ptr;
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// ============================================================================
|
|
738
|
+
// Scalar Types
|
|
739
|
+
// ============================================================================
|
|
740
|
+
|
|
741
|
+
class B8 extends RayObject {
|
|
742
|
+
static typeCode = -Types.B8;
|
|
743
|
+
|
|
744
|
+
get value() {
|
|
745
|
+
return this._sdk._readB8(this._ptr) !== 0;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
toJS() {
|
|
749
|
+
return this.value;
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
class U8 extends RayObject {
|
|
754
|
+
static typeCode = -Types.U8;
|
|
755
|
+
|
|
756
|
+
get value() {
|
|
757
|
+
return this._sdk._readU8(this._ptr);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
toJS() {
|
|
761
|
+
return this.value;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
class C8 extends RayObject {
|
|
766
|
+
static typeCode = -Types.C8;
|
|
767
|
+
|
|
768
|
+
get value() {
|
|
769
|
+
return String.fromCharCode(this._sdk._readC8(this._ptr));
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
toJS() {
|
|
773
|
+
return this.value;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
class I16 extends RayObject {
|
|
778
|
+
static typeCode = -Types.I16;
|
|
779
|
+
|
|
780
|
+
get value() {
|
|
781
|
+
return this._sdk._readI16(this._ptr);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
toJS() {
|
|
785
|
+
return this.value;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
class I32 extends RayObject {
|
|
790
|
+
static typeCode = -Types.I32;
|
|
791
|
+
|
|
792
|
+
get value() {
|
|
793
|
+
return this._sdk._readI32(this._ptr);
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
toJS() {
|
|
797
|
+
return this.value;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
class I64 extends RayObject {
|
|
802
|
+
static typeCode = -Types.I64;
|
|
803
|
+
|
|
804
|
+
get value() {
|
|
805
|
+
return this._sdk._readI64(this._ptr);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
toJS() {
|
|
809
|
+
return this.value;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
class F64 extends RayObject {
|
|
814
|
+
static typeCode = -Types.F64;
|
|
815
|
+
|
|
816
|
+
get value() {
|
|
817
|
+
return this._sdk._readF64(this._ptr);
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
toJS() {
|
|
821
|
+
return this.value;
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
class RayDate extends RayObject {
|
|
826
|
+
static typeCode = -Types.DATE;
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* Get days since 2000-01-01
|
|
830
|
+
*/
|
|
831
|
+
get value() {
|
|
832
|
+
return this._sdk._readDate(this._ptr);
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
/**
|
|
836
|
+
* Convert to JS Date
|
|
837
|
+
*/
|
|
838
|
+
toJS() {
|
|
839
|
+
const epoch = new Date(2000, 0, 1);
|
|
840
|
+
return new Date(epoch.getTime() + this.value * 24 * 60 * 60 * 1000);
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
class RayTime extends RayObject {
|
|
845
|
+
static typeCode = -Types.TIME;
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Get milliseconds since midnight
|
|
849
|
+
*/
|
|
850
|
+
get value() {
|
|
851
|
+
return this._sdk._readTime(this._ptr);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
toJS() {
|
|
855
|
+
const ms = this.value;
|
|
856
|
+
const hours = Math.floor(ms / 3600000);
|
|
857
|
+
const minutes = Math.floor((ms % 3600000) / 60000);
|
|
858
|
+
const seconds = Math.floor((ms % 60000) / 1000);
|
|
859
|
+
const millis = ms % 1000;
|
|
860
|
+
return { hours, minutes, seconds, milliseconds: millis };
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
class RayTimestamp extends RayObject {
|
|
865
|
+
static typeCode = -Types.TIMESTAMP;
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Get nanoseconds since 2000-01-01
|
|
869
|
+
*/
|
|
870
|
+
get value() {
|
|
871
|
+
return this._sdk._readTimestamp(this._ptr);
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
toJS() {
|
|
875
|
+
const epoch = new Date(2000, 0, 1);
|
|
876
|
+
return new Date(epoch.getTime() + this.value / 1000000);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
class Symbol extends RayObject {
|
|
881
|
+
static typeCode = -Types.SYMBOL;
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Get interned symbol ID
|
|
885
|
+
*/
|
|
886
|
+
get id() {
|
|
887
|
+
return this._sdk._readSymbolId(this._ptr);
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
/**
|
|
891
|
+
* Get symbol string value
|
|
892
|
+
*/
|
|
893
|
+
get value() {
|
|
894
|
+
return this._sdk._symbolToStr(this.id);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
toJS() {
|
|
898
|
+
return this.value;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
class GUID extends RayObject {
|
|
903
|
+
static typeCode = -Types.GUID;
|
|
904
|
+
|
|
905
|
+
toJS() {
|
|
906
|
+
// Format GUID bytes as string
|
|
907
|
+
return this.toString();
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
// ============================================================================
|
|
912
|
+
// Null and Error Types
|
|
913
|
+
// ============================================================================
|
|
914
|
+
|
|
915
|
+
class RayNull extends RayObject {
|
|
916
|
+
static typeCode = Types.NULL;
|
|
917
|
+
|
|
918
|
+
get isNull() {
|
|
919
|
+
return true;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
toJS() {
|
|
923
|
+
return null;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
class RayError extends RayObject {
|
|
928
|
+
static typeCode = Types.ERR;
|
|
929
|
+
|
|
930
|
+
get isError() {
|
|
931
|
+
return true;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
get message() {
|
|
935
|
+
return this.toString();
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
toJS() {
|
|
939
|
+
throw new Error(this.message);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// ============================================================================
|
|
944
|
+
// Vector with Zero-Copy TypedArray View
|
|
945
|
+
// ============================================================================
|
|
946
|
+
|
|
947
|
+
class Vector extends RayObject {
|
|
948
|
+
constructor(sdk, ptr, elementType) {
|
|
949
|
+
super(sdk, ptr);
|
|
950
|
+
this._elementType = elementType !== undefined ? elementType : sdk._getObjType(ptr);
|
|
951
|
+
this._typedArray = null;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
get elementType() {
|
|
955
|
+
return this._elementType;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
/**
|
|
959
|
+
* Get zero-copy TypedArray view over the vector data.
|
|
960
|
+
* WARNING: This view is only valid while the Vector exists.
|
|
961
|
+
* @returns {TypedArray}
|
|
962
|
+
*/
|
|
963
|
+
get typedArray() {
|
|
964
|
+
if (this._typedArray === null) {
|
|
965
|
+
const ArrayType = TYPED_ARRAY_MAP[this._elementType];
|
|
966
|
+
if (!ArrayType) {
|
|
967
|
+
throw new Error(`No TypedArray for type ${this._elementType}`);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
const dataPtr = this._sdk._getDataPtr(this._ptr);
|
|
971
|
+
const byteSize = this._sdk._getDataByteSize(this._ptr);
|
|
972
|
+
const elementSize = ELEMENT_SIZES[this._elementType];
|
|
973
|
+
const length = byteSize / elementSize;
|
|
974
|
+
|
|
975
|
+
// Create view over WASM memory
|
|
976
|
+
this._typedArray = new ArrayType(
|
|
977
|
+
this._sdk._wasm.HEAPU8.buffer,
|
|
978
|
+
dataPtr,
|
|
979
|
+
length
|
|
980
|
+
);
|
|
981
|
+
}
|
|
982
|
+
return this._typedArray;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* Get element at index
|
|
987
|
+
* @param {number} idx
|
|
988
|
+
* @param {boolean} [raw=false] - If true, return raw value without conversion
|
|
989
|
+
* @returns {any}
|
|
990
|
+
*/
|
|
991
|
+
at(idx, raw = false) {
|
|
992
|
+
if (idx < 0) idx = this.length + idx;
|
|
993
|
+
if (idx < 0 || idx >= this.length) {
|
|
994
|
+
throw new RangeError(`Index ${idx} out of bounds [0, ${this.length})`);
|
|
995
|
+
}
|
|
996
|
+
const val = this.typedArray[idx];
|
|
997
|
+
|
|
998
|
+
// Convert symbol IDs to strings
|
|
999
|
+
if (!raw && this._elementType === Types.SYMBOL) {
|
|
1000
|
+
return this._sdk._symbolToStr(Number(val));
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
// Convert BigInt to Number if safe
|
|
1004
|
+
if (!raw && typeof val === 'bigint') {
|
|
1005
|
+
const n = Number(val);
|
|
1006
|
+
if (Number.isSafeInteger(n)) return n;
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
return val;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* Set element at index
|
|
1014
|
+
* @param {number} idx
|
|
1015
|
+
* @param {any} value
|
|
1016
|
+
*/
|
|
1017
|
+
set(idx, value) {
|
|
1018
|
+
if (idx < 0) idx = this.length + idx;
|
|
1019
|
+
if (idx < 0 || idx >= this.length) {
|
|
1020
|
+
throw new RangeError(`Index ${idx} out of bounds [0, ${this.length})`);
|
|
1021
|
+
}
|
|
1022
|
+
this.typedArray[idx] = value;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* Convert to JS array (copies data)
|
|
1027
|
+
* @returns {Array}
|
|
1028
|
+
*/
|
|
1029
|
+
toJS() {
|
|
1030
|
+
const arr = Array.from(this.typedArray);
|
|
1031
|
+
|
|
1032
|
+
// Convert BigInt to Number for I64 types if safe
|
|
1033
|
+
if (this._elementType === Types.I64 ||
|
|
1034
|
+
this._elementType === Types.TIMESTAMP ||
|
|
1035
|
+
this._elementType === Types.SYMBOL) {
|
|
1036
|
+
return arr.map(v => {
|
|
1037
|
+
if (this._elementType === Types.SYMBOL) {
|
|
1038
|
+
return this._sdk._symbolToStr(Number(v));
|
|
1039
|
+
}
|
|
1040
|
+
const n = Number(v);
|
|
1041
|
+
return Number.isSafeInteger(n) ? n : v;
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
return arr;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Iterator support
|
|
1050
|
+
*/
|
|
1051
|
+
*[globalThis.Symbol.iterator]() {
|
|
1052
|
+
const view = this.typedArray;
|
|
1053
|
+
for (let i = 0; i < view.length; i++) {
|
|
1054
|
+
yield view[i];
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
// ============================================================================
|
|
1060
|
+
// String (Character Vector)
|
|
1061
|
+
// ============================================================================
|
|
1062
|
+
|
|
1063
|
+
class RayString extends Vector {
|
|
1064
|
+
constructor(sdk, ptr) {
|
|
1065
|
+
super(sdk, ptr, Types.C8);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
/**
|
|
1069
|
+
* Get string value
|
|
1070
|
+
* @returns {string}
|
|
1071
|
+
*/
|
|
1072
|
+
get value() {
|
|
1073
|
+
const decoder = new TextDecoder('utf-8');
|
|
1074
|
+
return decoder.decode(this.typedArray);
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
toJS() {
|
|
1078
|
+
return this.value;
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
toString() {
|
|
1082
|
+
return this.value;
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// ============================================================================
|
|
1087
|
+
// List (Mixed-Type Container)
|
|
1088
|
+
// ============================================================================
|
|
1089
|
+
|
|
1090
|
+
class List extends RayObject {
|
|
1091
|
+
/**
|
|
1092
|
+
* Get element at index
|
|
1093
|
+
* @param {number} idx
|
|
1094
|
+
* @returns {RayObject}
|
|
1095
|
+
*/
|
|
1096
|
+
at(idx) {
|
|
1097
|
+
if (idx < 0) idx = this.length + idx;
|
|
1098
|
+
if (idx < 0 || idx >= this.length) {
|
|
1099
|
+
throw new RangeError(`Index ${idx} out of bounds [0, ${this.length})`);
|
|
1100
|
+
}
|
|
1101
|
+
const ptr = this._sdk._atIdx(this._ptr, idx);
|
|
1102
|
+
return this._sdk._wrapPtr(ptr);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
/**
|
|
1106
|
+
* Set element at index
|
|
1107
|
+
* @param {number} idx
|
|
1108
|
+
* @param {RayObject|any} value
|
|
1109
|
+
*/
|
|
1110
|
+
set(idx, value) {
|
|
1111
|
+
if (idx < 0) idx = this.length + idx;
|
|
1112
|
+
const obj = value instanceof RayObject ? value : this._sdk._toRayObject(value);
|
|
1113
|
+
this._sdk._wasm.ccall('ins_obj', 'number',
|
|
1114
|
+
['number', 'number', 'number'],
|
|
1115
|
+
[this._ptr, idx, obj._ptr]);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/**
|
|
1119
|
+
* Push element to end
|
|
1120
|
+
* @param {RayObject|any} value
|
|
1121
|
+
*/
|
|
1122
|
+
push(value) {
|
|
1123
|
+
const obj = value instanceof RayObject ? value : this._sdk._toRayObject(value);
|
|
1124
|
+
// Use stack allocation for the pointer-to-pointer
|
|
1125
|
+
const stackSave = this._sdk._wasm.stackSave();
|
|
1126
|
+
const ptrPtr = this._sdk._wasm.stackAlloc(4);
|
|
1127
|
+
this._sdk._wasm.setValue(ptrPtr, this._ptr, 'i32');
|
|
1128
|
+
this._sdk._pushObj(ptrPtr, obj._ptr);
|
|
1129
|
+
this._ptr = this._sdk._wasm.getValue(ptrPtr, 'i32');
|
|
1130
|
+
this._sdk._wasm.stackRestore(stackSave);
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
/**
|
|
1134
|
+
* Convert to JS array
|
|
1135
|
+
* @returns {Array}
|
|
1136
|
+
*/
|
|
1137
|
+
toJS() {
|
|
1138
|
+
const result = [];
|
|
1139
|
+
for (let i = 0; i < this.length; i++) {
|
|
1140
|
+
result.push(this.at(i).toJS());
|
|
1141
|
+
}
|
|
1142
|
+
return result;
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
*[globalThis.Symbol.iterator]() {
|
|
1146
|
+
for (let i = 0; i < this.length; i++) {
|
|
1147
|
+
yield this.at(i);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
// ============================================================================
|
|
1153
|
+
// Dict (Key-Value Mapping)
|
|
1154
|
+
// ============================================================================
|
|
1155
|
+
|
|
1156
|
+
class Dict extends RayObject {
|
|
1157
|
+
/**
|
|
1158
|
+
* Get keys as symbol vector
|
|
1159
|
+
* @returns {Vector}
|
|
1160
|
+
*/
|
|
1161
|
+
keys() {
|
|
1162
|
+
return this._sdk._wrapPtr(this._sdk._dictKeys(this._ptr));
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Get values as list
|
|
1167
|
+
* @returns {List}
|
|
1168
|
+
*/
|
|
1169
|
+
values() {
|
|
1170
|
+
return this._sdk._wrapPtr(this._sdk._dictVals(this._ptr));
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
/**
|
|
1174
|
+
* Get value by key
|
|
1175
|
+
* @param {string|Symbol} key
|
|
1176
|
+
* @returns {RayObject}
|
|
1177
|
+
*/
|
|
1178
|
+
get(key) {
|
|
1179
|
+
const keyObj = typeof key === 'string' ? this._sdk.symbol(key) : key;
|
|
1180
|
+
const ptr = this._sdk._dictGet(this._ptr, keyObj._ptr);
|
|
1181
|
+
return this._sdk._wrapPtr(ptr);
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
/**
|
|
1185
|
+
* Check if key exists
|
|
1186
|
+
* @param {string} key
|
|
1187
|
+
* @returns {boolean}
|
|
1188
|
+
*/
|
|
1189
|
+
has(key) {
|
|
1190
|
+
return !this.get(key).isNull;
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* Convert to JS object
|
|
1195
|
+
* @returns {Object}
|
|
1196
|
+
*/
|
|
1197
|
+
toJS() {
|
|
1198
|
+
const result = {};
|
|
1199
|
+
const keys = this.keys();
|
|
1200
|
+
const vals = this.values();
|
|
1201
|
+
|
|
1202
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1203
|
+
const keyStr = this._sdk._symbolToStr(Number(keys.at(i)));
|
|
1204
|
+
result[keyStr] = vals.at(i).toJS();
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
return result;
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
*[globalThis.Symbol.iterator]() {
|
|
1211
|
+
const keys = this.keys();
|
|
1212
|
+
const vals = this.values();
|
|
1213
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1214
|
+
const keyStr = this._sdk._symbolToStr(Number(keys.at(i)));
|
|
1215
|
+
yield [keyStr, vals.at(i)];
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// ============================================================================
|
|
1221
|
+
// Table
|
|
1222
|
+
// ============================================================================
|
|
1223
|
+
|
|
1224
|
+
class Table extends RayObject {
|
|
1225
|
+
/**
|
|
1226
|
+
* Get column names
|
|
1227
|
+
* @returns {Vector}
|
|
1228
|
+
*/
|
|
1229
|
+
columns() {
|
|
1230
|
+
return this._sdk._wrapPtr(this._sdk._tableKeys(this._ptr));
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
/**
|
|
1234
|
+
* Get column names as string array
|
|
1235
|
+
* @returns {string[]}
|
|
1236
|
+
*/
|
|
1237
|
+
columnNames() {
|
|
1238
|
+
const cols = this.columns();
|
|
1239
|
+
const names = [];
|
|
1240
|
+
for (let i = 0; i < cols.length; i++) {
|
|
1241
|
+
// at() already converts symbol IDs to strings
|
|
1242
|
+
names.push(cols.at(i));
|
|
1243
|
+
}
|
|
1244
|
+
return names;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
/**
|
|
1248
|
+
* Get all values as list of vectors
|
|
1249
|
+
* @returns {List}
|
|
1250
|
+
*/
|
|
1251
|
+
values() {
|
|
1252
|
+
return this._sdk._wrapPtr(this._sdk._tableVals(this._ptr));
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
/**
|
|
1256
|
+
* Get column by name
|
|
1257
|
+
* @param {string} name
|
|
1258
|
+
* @returns {Vector}
|
|
1259
|
+
*/
|
|
1260
|
+
col(name) {
|
|
1261
|
+
return this._sdk._wrapPtr(this._sdk._tableCol(this._ptr, name, name.length));
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* Get row by index
|
|
1266
|
+
* @param {number} idx
|
|
1267
|
+
* @returns {Dict}
|
|
1268
|
+
*/
|
|
1269
|
+
row(idx) {
|
|
1270
|
+
return this._sdk._wrapPtr(this._sdk._tableRow(this._ptr, idx));
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
/**
|
|
1274
|
+
* Get row count
|
|
1275
|
+
* @returns {number}
|
|
1276
|
+
*/
|
|
1277
|
+
get rowCount() {
|
|
1278
|
+
return this._sdk._tableCount(this._ptr);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
/**
|
|
1282
|
+
* Create a select query builder
|
|
1283
|
+
* @param {...string} cols - Column names to select
|
|
1284
|
+
* @returns {SelectQuery}
|
|
1285
|
+
*/
|
|
1286
|
+
select(...cols) {
|
|
1287
|
+
return new SelectQuery(this._sdk, this).select(...cols);
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
/**
|
|
1291
|
+
* Create a where clause
|
|
1292
|
+
* @param {Expression} condition
|
|
1293
|
+
* @returns {SelectQuery}
|
|
1294
|
+
*/
|
|
1295
|
+
where(condition) {
|
|
1296
|
+
return new SelectQuery(this._sdk, this).where(condition);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* Insert data into table
|
|
1301
|
+
* @param {Object|Array} data
|
|
1302
|
+
* @returns {Table}
|
|
1303
|
+
*/
|
|
1304
|
+
insert(data) {
|
|
1305
|
+
let insertData;
|
|
1306
|
+
if (Array.isArray(data)) {
|
|
1307
|
+
insertData = this._sdk.list(data.map(v => this._sdk._toRayObject(v)));
|
|
1308
|
+
} else {
|
|
1309
|
+
insertData = this._sdk.dict(data);
|
|
1310
|
+
}
|
|
1311
|
+
const newPtr = this._sdk._tableInsert(this._ptr, insertData._ptr);
|
|
1312
|
+
return this._sdk._wrapPtr(newPtr);
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
/**
|
|
1316
|
+
* Convert to JS object with column arrays
|
|
1317
|
+
* @returns {Object}
|
|
1318
|
+
*/
|
|
1319
|
+
toJS() {
|
|
1320
|
+
const result = {};
|
|
1321
|
+
const names = this.columnNames();
|
|
1322
|
+
const vals = this.values();
|
|
1323
|
+
|
|
1324
|
+
for (let i = 0; i < names.length; i++) {
|
|
1325
|
+
result[names[i]] = vals.at(i).toJS();
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
return result;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
/**
|
|
1332
|
+
* Convert to array of row objects
|
|
1333
|
+
* @returns {Object[]}
|
|
1334
|
+
*/
|
|
1335
|
+
toRows() {
|
|
1336
|
+
const names = this.columnNames();
|
|
1337
|
+
const count = this.rowCount;
|
|
1338
|
+
const rows = [];
|
|
1339
|
+
|
|
1340
|
+
for (let i = 0; i < count; i++) {
|
|
1341
|
+
const row = {};
|
|
1342
|
+
for (const name of names) {
|
|
1343
|
+
row[name] = this.col(name).at(i);
|
|
1344
|
+
if (typeof row[name] === 'bigint') {
|
|
1345
|
+
const n = Number(row[name]);
|
|
1346
|
+
row[name] = Number.isSafeInteger(n) ? n : row[name];
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
rows.push(row);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
return rows;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
// ============================================================================
|
|
1357
|
+
// Lambda (Function)
|
|
1358
|
+
// ============================================================================
|
|
1359
|
+
|
|
1360
|
+
class Lambda extends RayObject {
|
|
1361
|
+
/**
|
|
1362
|
+
* Call the lambda with arguments
|
|
1363
|
+
* @param {...any} args
|
|
1364
|
+
* @returns {RayObject}
|
|
1365
|
+
*/
|
|
1366
|
+
call(...args) {
|
|
1367
|
+
// Build call expression
|
|
1368
|
+
const argList = args.map(a => {
|
|
1369
|
+
if (a instanceof RayObject) return a.toString();
|
|
1370
|
+
if (typeof a === 'string') return `\`${a}`;
|
|
1371
|
+
return String(a);
|
|
1372
|
+
}).join(' ');
|
|
1373
|
+
|
|
1374
|
+
const expr = `(${this.toString()} ${argList})`;
|
|
1375
|
+
return this._sdk.eval(expr);
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// ============================================================================
|
|
1380
|
+
// Query Builder
|
|
1381
|
+
// ============================================================================
|
|
1382
|
+
|
|
1383
|
+
/**
|
|
1384
|
+
* Expression builder for query conditions
|
|
1385
|
+
*/
|
|
1386
|
+
class Expr {
|
|
1387
|
+
constructor(sdk, parts) {
|
|
1388
|
+
this._sdk = sdk;
|
|
1389
|
+
this._parts = parts;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
/**
|
|
1393
|
+
* Create a column reference
|
|
1394
|
+
* @param {string} name
|
|
1395
|
+
* @returns {Expr}
|
|
1396
|
+
*/
|
|
1397
|
+
static col(sdk, name) {
|
|
1398
|
+
return new Expr(sdk, [`\`${name}`]);
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
// Comparison operators
|
|
1402
|
+
eq(value) { return this._binOp('=', value); }
|
|
1403
|
+
ne(value) { return this._binOp('<>', value); }
|
|
1404
|
+
lt(value) { return this._binOp('<', value); }
|
|
1405
|
+
le(value) { return this._binOp('<=', value); }
|
|
1406
|
+
gt(value) { return this._binOp('>', value); }
|
|
1407
|
+
ge(value) { return this._binOp('>=', value); }
|
|
1408
|
+
|
|
1409
|
+
// Logical operators
|
|
1410
|
+
and(other) { return this._logicOp('and', other); }
|
|
1411
|
+
or(other) { return this._logicOp('or', other); }
|
|
1412
|
+
not() { return new Expr(this._sdk, ['(not', ...this._parts, ')']); }
|
|
1413
|
+
|
|
1414
|
+
// Aggregations
|
|
1415
|
+
sum() { return new Expr(this._sdk, ['(sum', ...this._parts, ')']); }
|
|
1416
|
+
avg() { return new Expr(this._sdk, ['(avg', ...this._parts, ')']); }
|
|
1417
|
+
min() { return new Expr(this._sdk, ['(min', ...this._parts, ')']); }
|
|
1418
|
+
max() { return new Expr(this._sdk, ['(max', ...this._parts, ')']); }
|
|
1419
|
+
count() { return new Expr(this._sdk, ['(count', ...this._parts, ')']); }
|
|
1420
|
+
first() { return new Expr(this._sdk, ['(first', ...this._parts, ')']); }
|
|
1421
|
+
last() { return new Expr(this._sdk, ['(last', ...this._parts, ')']); }
|
|
1422
|
+
distinct() { return new Expr(this._sdk, ['(distinct', ...this._parts, ')']); }
|
|
1423
|
+
|
|
1424
|
+
_binOp(op, value) {
|
|
1425
|
+
const valStr = this._valueToStr(value);
|
|
1426
|
+
return new Expr(this._sdk, [`(${op}`, ...this._parts, valStr, ')']);
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
_logicOp(op, other) {
|
|
1430
|
+
return new Expr(this._sdk, [`(${op}`, ...this._parts, ...other._parts, ')']);
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
_valueToStr(value) {
|
|
1434
|
+
if (value instanceof Expr) return value.toString();
|
|
1435
|
+
if (typeof value === 'string') return `"${value}"`;
|
|
1436
|
+
if (value instanceof Date) {
|
|
1437
|
+
// Format as Rayforce timestamp
|
|
1438
|
+
return value.toISOString();
|
|
1439
|
+
}
|
|
1440
|
+
return String(value);
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
toString() {
|
|
1444
|
+
return this._parts.join(' ');
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
/**
|
|
1449
|
+
* SELECT query builder
|
|
1450
|
+
*/
|
|
1451
|
+
class SelectQuery {
|
|
1452
|
+
constructor(sdk, table) {
|
|
1453
|
+
this._sdk = sdk;
|
|
1454
|
+
this._table = table;
|
|
1455
|
+
this._selectCols = null;
|
|
1456
|
+
this._whereCond = null;
|
|
1457
|
+
this._byCols = null;
|
|
1458
|
+
this._computedCols = {};
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
/**
|
|
1462
|
+
* Specify columns to select
|
|
1463
|
+
* @param {...string|Expr} cols
|
|
1464
|
+
* @returns {SelectQuery}
|
|
1465
|
+
*/
|
|
1466
|
+
select(...cols) {
|
|
1467
|
+
const q = this._clone();
|
|
1468
|
+
q._selectCols = cols;
|
|
1469
|
+
return q;
|
|
1470
|
+
}
|
|
1471
|
+
|
|
1472
|
+
/**
|
|
1473
|
+
* Add computed column
|
|
1474
|
+
* @param {string} name
|
|
1475
|
+
* @param {Expr} expr
|
|
1476
|
+
* @returns {SelectQuery}
|
|
1477
|
+
*/
|
|
1478
|
+
withColumn(name, expr) {
|
|
1479
|
+
const q = this._clone();
|
|
1480
|
+
q._computedCols[name] = expr;
|
|
1481
|
+
return q;
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
/**
|
|
1485
|
+
* Add WHERE condition
|
|
1486
|
+
* @param {Expr} condition
|
|
1487
|
+
* @returns {SelectQuery}
|
|
1488
|
+
*/
|
|
1489
|
+
where(condition) {
|
|
1490
|
+
const q = this._clone();
|
|
1491
|
+
q._whereCond = q._whereCond ? q._whereCond.and(condition) : condition;
|
|
1492
|
+
return q;
|
|
1493
|
+
}
|
|
1494
|
+
|
|
1495
|
+
/**
|
|
1496
|
+
* Add GROUP BY columns
|
|
1497
|
+
* @param {...string} cols
|
|
1498
|
+
* @returns {SelectQuery}
|
|
1499
|
+
*/
|
|
1500
|
+
groupBy(...cols) {
|
|
1501
|
+
const q = this._clone();
|
|
1502
|
+
q._byCols = cols;
|
|
1503
|
+
return q;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
/**
|
|
1507
|
+
* Column reference helper
|
|
1508
|
+
* @param {string} name
|
|
1509
|
+
* @returns {Expr}
|
|
1510
|
+
*/
|
|
1511
|
+
col(name) {
|
|
1512
|
+
return Expr.col(this._sdk, name);
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
/**
|
|
1516
|
+
* Execute the query
|
|
1517
|
+
* @returns {Table}
|
|
1518
|
+
*/
|
|
1519
|
+
execute() {
|
|
1520
|
+
// Build query dict
|
|
1521
|
+
const query = {};
|
|
1522
|
+
|
|
1523
|
+
// from clause
|
|
1524
|
+
query.from = this._table._ptr;
|
|
1525
|
+
|
|
1526
|
+
// select columns
|
|
1527
|
+
if (this._selectCols) {
|
|
1528
|
+
for (const col of this._selectCols) {
|
|
1529
|
+
if (typeof col === 'string') {
|
|
1530
|
+
query[col] = col;
|
|
1531
|
+
} else if (col instanceof Expr) {
|
|
1532
|
+
// Need alias for expressions
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
// computed columns
|
|
1538
|
+
for (const [name, expr] of Object.entries(this._computedCols)) {
|
|
1539
|
+
query[name] = expr.toString();
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
// where clause
|
|
1543
|
+
if (this._whereCond) {
|
|
1544
|
+
query.where = this._whereCond.toString();
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
// group by
|
|
1548
|
+
if (this._byCols) {
|
|
1549
|
+
query.by = {};
|
|
1550
|
+
for (const col of this._byCols) {
|
|
1551
|
+
query.by[col] = col;
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
// Build and execute query
|
|
1556
|
+
const queryDict = this._sdk.dict(query);
|
|
1557
|
+
return this._sdk._wrapPtr(this._sdk._querySelect(queryDict._ptr));
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
_clone() {
|
|
1561
|
+
const q = new SelectQuery(this._sdk, this._table);
|
|
1562
|
+
q._selectCols = this._selectCols;
|
|
1563
|
+
q._whereCond = this._whereCond;
|
|
1564
|
+
q._byCols = this._byCols;
|
|
1565
|
+
q._computedCols = { ...this._computedCols };
|
|
1566
|
+
return q;
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
// ============================================================================
|
|
1571
|
+
// Exports
|
|
1572
|
+
// ============================================================================
|
|
1573
|
+
|
|
1574
|
+
export {
|
|
1575
|
+
RayforceSDK,
|
|
1576
|
+
RayObject,
|
|
1577
|
+
RayNull,
|
|
1578
|
+
RayError,
|
|
1579
|
+
B8, U8, C8, I16, I32, I64, F64,
|
|
1580
|
+
RayDate, RayTime, RayTimestamp,
|
|
1581
|
+
Symbol, GUID,
|
|
1582
|
+
Vector, RayString, List, Dict, Table, Lambda,
|
|
1583
|
+
Expr, SelectQuery,
|
|
1584
|
+
};
|
|
1585
|
+
|
|
1586
|
+
// Default export for UMD/CDN usage
|
|
1587
|
+
export default {
|
|
1588
|
+
createRayforceSDK,
|
|
1589
|
+
Types,
|
|
1590
|
+
Expr,
|
|
1591
|
+
};
|