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.
@@ -0,0 +1,933 @@
1
+ /**
2
+ * RayforceDB UMD Bundle
3
+ *
4
+ * This file provides a UMD (Universal Module Definition) wrapper
5
+ * for browser usage via script tag.
6
+ *
7
+ * Usage:
8
+ * <script src="rayforce.umd.js"></script>
9
+ * <script>
10
+ * Rayforce.init().then(rf => {
11
+ * console.log(rf.eval('(+ 1 2 3)').toJS()); // 6
12
+ * });
13
+ * </script>
14
+ */
15
+
16
+ (function(root, factory) {
17
+ if (typeof define === 'function' && define.amd) {
18
+ // AMD
19
+ define([], factory);
20
+ } else if (typeof module === 'object' && module.exports) {
21
+ // CommonJS
22
+ module.exports = factory();
23
+ } else {
24
+ // Browser global
25
+ root.Rayforce = factory();
26
+ }
27
+ }(typeof self !== 'undefined' ? self : this, function() {
28
+ 'use strict';
29
+
30
+ // ============================================================================
31
+ // Type Constants
32
+ // ============================================================================
33
+
34
+ const Types = Object.freeze({
35
+ LIST: 0,
36
+ B8: 1,
37
+ U8: 2,
38
+ I16: 3,
39
+ I32: 4,
40
+ I64: 5,
41
+ SYMBOL: 6,
42
+ DATE: 7,
43
+ TIME: 8,
44
+ TIMESTAMP: 9,
45
+ F64: 10,
46
+ GUID: 11,
47
+ C8: 12,
48
+ TABLE: 98,
49
+ DICT: 99,
50
+ LAMBDA: 100,
51
+ NULL: 126,
52
+ ERR: 127,
53
+ });
54
+
55
+ // Element sizes for each type (in bytes)
56
+ const ELEMENT_SIZES = {
57
+ [Types.B8]: 1,
58
+ [Types.U8]: 1,
59
+ [Types.C8]: 1,
60
+ [Types.I16]: 2,
61
+ [Types.I32]: 4,
62
+ [Types.I64]: 8,
63
+ [Types.F64]: 8,
64
+ [Types.DATE]: 4,
65
+ [Types.TIME]: 4,
66
+ [Types.TIMESTAMP]: 8,
67
+ [Types.SYMBOL]: 8,
68
+ [Types.GUID]: 16,
69
+ [Types.LIST]: 4,
70
+ };
71
+
72
+ // TypedArray constructors for each type
73
+ const TYPED_ARRAY_MAP = {
74
+ [Types.B8]: Int8Array,
75
+ [Types.U8]: Uint8Array,
76
+ [Types.C8]: Uint8Array,
77
+ [Types.I16]: Int16Array,
78
+ [Types.I32]: Int32Array,
79
+ [Types.I64]: BigInt64Array,
80
+ [Types.F64]: Float64Array,
81
+ [Types.DATE]: Int32Array,
82
+ [Types.TIME]: Int32Array,
83
+ [Types.TIMESTAMP]: BigInt64Array,
84
+ [Types.SYMBOL]: BigInt64Array,
85
+ };
86
+
87
+ // ============================================================================
88
+ // RayObject Base Class
89
+ // ============================================================================
90
+
91
+ class RayObject {
92
+ constructor(sdk, ptr) {
93
+ this._sdk = sdk;
94
+ this._ptr = ptr;
95
+ this._owned = true;
96
+ }
97
+
98
+ get ptr() { return this._ptr; }
99
+ get type() { return this._sdk._getObjType(this._ptr); }
100
+ get absType() { const t = this.type; return t < 0 ? -t : t; }
101
+ get isAtom() { return this._sdk._isObjAtom(this._ptr) !== 0; }
102
+ get isVector() { return this._sdk._isObjVector(this._ptr) !== 0; }
103
+ get isNull() { return this._sdk._isObjNull(this._ptr) !== 0; }
104
+ get isError() { return this._sdk._isObjError(this._ptr) !== 0; }
105
+ get length() { return this._sdk._getObjLen(this._ptr); }
106
+ get refCount() { return this._sdk._getObjRc(this._ptr); }
107
+
108
+ clone() { return this._sdk._wrapPtr(this._sdk._cloneObj(this._ptr)); }
109
+ toString() { return this._sdk.format(this._ptr); }
110
+ toJS() { return this.toString(); }
111
+
112
+ drop() {
113
+ if (this._owned && this._ptr !== 0) {
114
+ this._sdk._dropObj(this._ptr);
115
+ this._ptr = 0;
116
+ this._owned = false;
117
+ }
118
+ }
119
+
120
+ release() {
121
+ this._owned = false;
122
+ return this._ptr;
123
+ }
124
+ }
125
+
126
+ // ============================================================================
127
+ // Scalar Types
128
+ // ============================================================================
129
+
130
+ class B8 extends RayObject {
131
+ get value() { return this._sdk._readB8(this._ptr) !== 0; }
132
+ toJS() { return this.value; }
133
+ }
134
+
135
+ class U8 extends RayObject {
136
+ get value() { return this._sdk._readU8(this._ptr); }
137
+ toJS() { return this.value; }
138
+ }
139
+
140
+ class C8 extends RayObject {
141
+ get value() { return String.fromCharCode(this._sdk._readC8(this._ptr)); }
142
+ toJS() { return this.value; }
143
+ }
144
+
145
+ class I16 extends RayObject {
146
+ get value() { return this._sdk._readI16(this._ptr); }
147
+ toJS() { return this.value; }
148
+ }
149
+
150
+ class I32 extends RayObject {
151
+ get value() { return this._sdk._readI32(this._ptr); }
152
+ toJS() { return this.value; }
153
+ }
154
+
155
+ class I64 extends RayObject {
156
+ get value() { return this._sdk._readI64(this._ptr); }
157
+ toJS() { return this.value; }
158
+ }
159
+
160
+ class F64 extends RayObject {
161
+ get value() { return this._sdk._readF64(this._ptr); }
162
+ toJS() { return this.value; }
163
+ }
164
+
165
+ class RayDate extends RayObject {
166
+ get value() { return this._sdk._readDate(this._ptr); }
167
+ toJS() {
168
+ const epoch = new Date(2000, 0, 1);
169
+ return new Date(epoch.getTime() + this.value * 24 * 60 * 60 * 1000);
170
+ }
171
+ }
172
+
173
+ class RayTime extends RayObject {
174
+ get value() { return this._sdk._readTime(this._ptr); }
175
+ toJS() {
176
+ const ms = this.value;
177
+ return {
178
+ hours: Math.floor(ms / 3600000),
179
+ minutes: Math.floor((ms % 3600000) / 60000),
180
+ seconds: Math.floor((ms % 60000) / 1000),
181
+ milliseconds: ms % 1000
182
+ };
183
+ }
184
+ }
185
+
186
+ class RayTimestamp extends RayObject {
187
+ get value() { return this._sdk._readTimestamp(this._ptr); }
188
+ toJS() {
189
+ const epoch = new Date(2000, 0, 1);
190
+ return new Date(epoch.getTime() + this.value / 1000000);
191
+ }
192
+ }
193
+
194
+ class RaySymbol extends RayObject {
195
+ get id() { return this._sdk._readSymbolId(this._ptr); }
196
+ get value() { return this._sdk._symbolToStr(this.id); }
197
+ toJS() { return this.value; }
198
+ }
199
+
200
+ class GUID extends RayObject {
201
+ toJS() { return this.toString(); }
202
+ }
203
+
204
+ class RayNull extends RayObject {
205
+ get isNull() { return true; }
206
+ toJS() { return null; }
207
+ }
208
+
209
+ class RayError extends RayObject {
210
+ get isError() { return true; }
211
+ get message() { return this.toString(); }
212
+ toJS() { throw new Error(this.message); }
213
+ }
214
+
215
+ // ============================================================================
216
+ // Vector with Zero-Copy TypedArray View
217
+ // ============================================================================
218
+
219
+ class Vector extends RayObject {
220
+ constructor(sdk, ptr, elementType) {
221
+ super(sdk, ptr);
222
+ this._elementType = elementType !== undefined ? elementType : sdk._getObjType(ptr);
223
+ this._typedArray = null;
224
+ }
225
+
226
+ get elementType() { return this._elementType; }
227
+
228
+ get typedArray() {
229
+ if (this._typedArray === null) {
230
+ const ArrayType = TYPED_ARRAY_MAP[this._elementType];
231
+ if (!ArrayType) throw new Error(`No TypedArray for type ${this._elementType}`);
232
+
233
+ const dataPtr = this._sdk._getDataPtr(this._ptr);
234
+ const byteSize = this._sdk._getDataByteSize(this._ptr);
235
+ const elementSize = ELEMENT_SIZES[this._elementType];
236
+ const length = byteSize / elementSize;
237
+
238
+ this._typedArray = new ArrayType(this._sdk._wasm.HEAPU8.buffer, dataPtr, length);
239
+ }
240
+ return this._typedArray;
241
+ }
242
+
243
+ at(idx) {
244
+ if (idx < 0) idx = this.length + idx;
245
+ if (idx < 0 || idx >= this.length) throw new RangeError(`Index ${idx} out of bounds`);
246
+ return this.typedArray[idx];
247
+ }
248
+
249
+ set(idx, value) {
250
+ if (idx < 0) idx = this.length + idx;
251
+ if (idx < 0 || idx >= this.length) throw new RangeError(`Index ${idx} out of bounds`);
252
+ this.typedArray[idx] = value;
253
+ }
254
+
255
+ toJS() {
256
+ const arr = Array.from(this.typedArray);
257
+ if (this._elementType === Types.I64 || this._elementType === Types.TIMESTAMP || this._elementType === Types.SYMBOL) {
258
+ return arr.map(v => {
259
+ if (this._elementType === Types.SYMBOL) return this._sdk._symbolToStr(Number(v));
260
+ const n = Number(v);
261
+ return Number.isSafeInteger(n) ? n : v;
262
+ });
263
+ }
264
+ return arr;
265
+ }
266
+
267
+ *[Symbol.iterator]() {
268
+ const view = this.typedArray;
269
+ for (let i = 0; i < view.length; i++) yield view[i];
270
+ }
271
+ }
272
+
273
+ // ============================================================================
274
+ // String (Character Vector)
275
+ // ============================================================================
276
+
277
+ class RayString extends Vector {
278
+ constructor(sdk, ptr) { super(sdk, ptr, Types.C8); }
279
+ get value() { return new TextDecoder('utf-8').decode(this.typedArray); }
280
+ toJS() { return this.value; }
281
+ toString() { return this.value; }
282
+ }
283
+
284
+ // ============================================================================
285
+ // List (Mixed-Type Container)
286
+ // ============================================================================
287
+
288
+ class List extends RayObject {
289
+ at(idx) {
290
+ if (idx < 0) idx = this.length + idx;
291
+ if (idx < 0 || idx >= this.length) throw new RangeError(`Index ${idx} out of bounds`);
292
+ return this._sdk._wrapPtr(this._sdk._atIdx(this._ptr, idx));
293
+ }
294
+
295
+ set(idx, value) {
296
+ if (idx < 0) idx = this.length + idx;
297
+ const obj = value instanceof RayObject ? value : this._sdk._toRayObject(value);
298
+ this._sdk._wasm.ccall('ins_obj', 'number', ['number', 'number', 'number'], [this._ptr, idx, obj._ptr]);
299
+ }
300
+
301
+ push(value) {
302
+ const obj = value instanceof RayObject ? value : this._sdk._toRayObject(value);
303
+ const stackSave = this._sdk._wasm.stackSave();
304
+ const ptrPtr = this._sdk._wasm.stackAlloc(4);
305
+ this._sdk._wasm.setValue(ptrPtr, this._ptr, 'i32');
306
+ this._sdk._pushObj(ptrPtr, obj._ptr);
307
+ this._ptr = this._sdk._wasm.getValue(ptrPtr, 'i32');
308
+ this._sdk._wasm.stackRestore(stackSave);
309
+ }
310
+
311
+ toJS() {
312
+ const result = [];
313
+ for (let i = 0; i < this.length; i++) result.push(this.at(i).toJS());
314
+ return result;
315
+ }
316
+
317
+ *[Symbol.iterator]() {
318
+ for (let i = 0; i < this.length; i++) yield this.at(i);
319
+ }
320
+ }
321
+
322
+ // ============================================================================
323
+ // Dict (Key-Value Mapping)
324
+ // ============================================================================
325
+
326
+ class Dict extends RayObject {
327
+ keys() { return this._sdk._wrapPtr(this._sdk._dictKeys(this._ptr)); }
328
+ values() { return this._sdk._wrapPtr(this._sdk._dictVals(this._ptr)); }
329
+
330
+ get(key) {
331
+ const keyObj = typeof key === 'string' ? this._sdk.symbol(key) : key;
332
+ return this._sdk._wrapPtr(this._sdk._dictGet(this._ptr, keyObj._ptr));
333
+ }
334
+
335
+ has(key) { return !this.get(key).isNull; }
336
+
337
+ toJS() {
338
+ const result = {};
339
+ const keys = this.keys();
340
+ const vals = this.values();
341
+ for (let i = 0; i < keys.length; i++) {
342
+ const keyStr = this._sdk._symbolToStr(Number(keys.at(i)));
343
+ result[keyStr] = vals.at(i).toJS();
344
+ }
345
+ return result;
346
+ }
347
+
348
+ *[Symbol.iterator]() {
349
+ const keys = this.keys();
350
+ const vals = this.values();
351
+ for (let i = 0; i < keys.length; i++) {
352
+ yield [this._sdk._symbolToStr(Number(keys.at(i))), vals.at(i)];
353
+ }
354
+ }
355
+ }
356
+
357
+ // ============================================================================
358
+ // Table
359
+ // ============================================================================
360
+
361
+ class Table extends RayObject {
362
+ columns() { return this._sdk._wrapPtr(this._sdk._tableKeys(this._ptr)); }
363
+
364
+ columnNames() {
365
+ const cols = this.columns();
366
+ const names = [];
367
+ for (let i = 0; i < cols.length; i++) {
368
+ names.push(this._sdk._symbolToStr(Number(cols.at(i))));
369
+ }
370
+ return names;
371
+ }
372
+
373
+ values() { return this._sdk._wrapPtr(this._sdk._tableVals(this._ptr)); }
374
+ col(name) { return this._sdk._wrapPtr(this._sdk._tableCol(this._ptr, name, name.length)); }
375
+ row(idx) { return this._sdk._wrapPtr(this._sdk._tableRow(this._ptr, idx)); }
376
+ get rowCount() { return this._sdk._tableCount(this._ptr); }
377
+
378
+ select(...cols) { return new SelectQuery(this._sdk, this).select(...cols); }
379
+ where(condition) { return new SelectQuery(this._sdk, this).where(condition); }
380
+
381
+ insert(data) {
382
+ let insertData;
383
+ if (Array.isArray(data)) {
384
+ insertData = this._sdk.list(data.map(v => this._sdk._toRayObject(v)));
385
+ } else {
386
+ insertData = this._sdk.dict(data);
387
+ }
388
+ return this._sdk._wrapPtr(this._sdk._tableInsert(this._ptr, insertData._ptr));
389
+ }
390
+
391
+ toJS() {
392
+ const result = {};
393
+ const names = this.columnNames();
394
+ const vals = this.values();
395
+ for (let i = 0; i < names.length; i++) {
396
+ result[names[i]] = vals.at(i).toJS();
397
+ }
398
+ return result;
399
+ }
400
+
401
+ toRows() {
402
+ const names = this.columnNames();
403
+ const count = this.rowCount;
404
+ const rows = [];
405
+ for (let i = 0; i < count; i++) {
406
+ const row = {};
407
+ for (const name of names) {
408
+ row[name] = this.col(name).at(i);
409
+ if (typeof row[name] === 'bigint') {
410
+ const n = Number(row[name]);
411
+ row[name] = Number.isSafeInteger(n) ? n : row[name];
412
+ }
413
+ }
414
+ rows.push(row);
415
+ }
416
+ return rows;
417
+ }
418
+ }
419
+
420
+ // ============================================================================
421
+ // Lambda (Function)
422
+ // ============================================================================
423
+
424
+ class Lambda extends RayObject {
425
+ call(...args) {
426
+ const argList = args.map(a => {
427
+ if (a instanceof RayObject) return a.toString();
428
+ if (typeof a === 'string') return `\`${a}`;
429
+ return String(a);
430
+ }).join(' ');
431
+ return this._sdk.eval(`(${this.toString()} ${argList})`);
432
+ }
433
+ }
434
+
435
+ // ============================================================================
436
+ // Expression Builder
437
+ // ============================================================================
438
+
439
+ class Expr {
440
+ constructor(sdk, parts) {
441
+ this._sdk = sdk;
442
+ this._parts = parts;
443
+ }
444
+
445
+ static col(sdk, name) { return new Expr(sdk, [`\`${name}`]); }
446
+
447
+ eq(value) { return this._binOp('=', value); }
448
+ ne(value) { return this._binOp('<>', value); }
449
+ lt(value) { return this._binOp('<', value); }
450
+ le(value) { return this._binOp('<=', value); }
451
+ gt(value) { return this._binOp('>', value); }
452
+ ge(value) { return this._binOp('>=', value); }
453
+
454
+ and(other) { return this._logicOp('and', other); }
455
+ or(other) { return this._logicOp('or', other); }
456
+ not() { return new Expr(this._sdk, ['(not', ...this._parts, ')']); }
457
+
458
+ sum() { return new Expr(this._sdk, ['(sum', ...this._parts, ')']); }
459
+ avg() { return new Expr(this._sdk, ['(avg', ...this._parts, ')']); }
460
+ min() { return new Expr(this._sdk, ['(min', ...this._parts, ')']); }
461
+ max() { return new Expr(this._sdk, ['(max', ...this._parts, ')']); }
462
+ count() { return new Expr(this._sdk, ['(count', ...this._parts, ')']); }
463
+ first() { return new Expr(this._sdk, ['(first', ...this._parts, ')']); }
464
+ last() { return new Expr(this._sdk, ['(last', ...this._parts, ')']); }
465
+ distinct() { return new Expr(this._sdk, ['(distinct', ...this._parts, ')']); }
466
+
467
+ _binOp(op, value) {
468
+ const valStr = this._valueToStr(value);
469
+ return new Expr(this._sdk, [`(${op}`, ...this._parts, valStr, ')']);
470
+ }
471
+
472
+ _logicOp(op, other) {
473
+ return new Expr(this._sdk, [`(${op}`, ...this._parts, ...other._parts, ')']);
474
+ }
475
+
476
+ _valueToStr(value) {
477
+ if (value instanceof Expr) return value.toString();
478
+ if (typeof value === 'string') return `"${value}"`;
479
+ return String(value);
480
+ }
481
+
482
+ toString() { return this._parts.join(' '); }
483
+ }
484
+
485
+ // ============================================================================
486
+ // SelectQuery Builder
487
+ // ============================================================================
488
+
489
+ class SelectQuery {
490
+ constructor(sdk, table) {
491
+ this._sdk = sdk;
492
+ this._table = table;
493
+ this._selectCols = null;
494
+ this._whereCond = null;
495
+ this._byCols = null;
496
+ this._computedCols = {};
497
+ }
498
+
499
+ select(...cols) {
500
+ const q = this._clone();
501
+ q._selectCols = cols;
502
+ return q;
503
+ }
504
+
505
+ withColumn(name, expr) {
506
+ const q = this._clone();
507
+ q._computedCols[name] = expr;
508
+ return q;
509
+ }
510
+
511
+ where(condition) {
512
+ const q = this._clone();
513
+ q._whereCond = q._whereCond ? q._whereCond.and(condition) : condition;
514
+ return q;
515
+ }
516
+
517
+ groupBy(...cols) {
518
+ const q = this._clone();
519
+ q._byCols = cols;
520
+ return q;
521
+ }
522
+
523
+ col(name) { return Expr.col(this._sdk, name); }
524
+
525
+ execute() {
526
+ const query = { from: this._table._ptr };
527
+ if (this._selectCols) {
528
+ for (const col of this._selectCols) {
529
+ if (typeof col === 'string') query[col] = col;
530
+ }
531
+ }
532
+ for (const [name, expr] of Object.entries(this._computedCols)) {
533
+ query[name] = expr.toString();
534
+ }
535
+ if (this._whereCond) query.where = this._whereCond.toString();
536
+ if (this._byCols) {
537
+ query.by = {};
538
+ for (const col of this._byCols) query.by[col] = col;
539
+ }
540
+ const queryDict = this._sdk.dict(query);
541
+ return this._sdk._wrapPtr(this._sdk._querySelect(queryDict._ptr));
542
+ }
543
+
544
+ _clone() {
545
+ const q = new SelectQuery(this._sdk, this._table);
546
+ q._selectCols = this._selectCols;
547
+ q._whereCond = this._whereCond;
548
+ q._byCols = this._byCols;
549
+ q._computedCols = { ...this._computedCols };
550
+ return q;
551
+ }
552
+ }
553
+
554
+ // ============================================================================
555
+ // Main SDK Class
556
+ // ============================================================================
557
+
558
+ class RayforceSDK {
559
+ constructor(wasm) {
560
+ this._wasm = wasm;
561
+ this._cmdCounter = 0;
562
+ this._setupBindings();
563
+ }
564
+
565
+ _setupBindings() {
566
+ const w = this._wasm;
567
+
568
+ this._evalCmd = w.cwrap('eval_cmd', 'number', ['string', 'string']);
569
+ this._evalStr = w.cwrap('eval_str', 'number', ['string']);
570
+ this._strOfObj = w.cwrap('strof_obj', 'string', ['number']);
571
+ this._dropObj = w.cwrap('drop_obj', null, ['number']);
572
+ this._cloneObj = w.cwrap('clone_obj', 'number', ['number']);
573
+ this._versionStr = w.cwrap('version_str', 'string', []);
574
+
575
+ this._getObjType = w.cwrap('get_obj_type', 'number', ['number']);
576
+ this._getObjLen = w.cwrap('get_obj_len', 'number', ['number']);
577
+ this._isObjAtom = w.cwrap('is_obj_atom', 'number', ['number']);
578
+ this._isObjVector = w.cwrap('is_obj_vector', 'number', ['number']);
579
+ this._isObjNull = w.cwrap('is_obj_null', 'number', ['number']);
580
+ this._isObjError = w.cwrap('is_obj_error', 'number', ['number']);
581
+ this._getObjRc = w.cwrap('get_obj_rc', 'number', ['number']);
582
+
583
+ this._getDataPtr = w.cwrap('get_data_ptr', 'number', ['number']);
584
+ this._getElementSize = w.cwrap('get_element_size', 'number', ['number']);
585
+ this._getDataByteSize = w.cwrap('get_data_byte_size', 'number', ['number']);
586
+
587
+ this._initB8 = w.cwrap('init_b8', 'number', ['number']);
588
+ this._initU8 = w.cwrap('init_u8', 'number', ['number']);
589
+ this._initC8 = w.cwrap('init_c8', 'number', ['number']);
590
+ this._initI16 = w.cwrap('init_i16', 'number', ['number']);
591
+ this._initI32 = w.cwrap('init_i32', 'number', ['number']);
592
+ this._initI64 = w.cwrap('init_i64', 'number', ['number']);
593
+ this._initF64 = w.cwrap('init_f64', 'number', ['number']);
594
+ this._initDate = w.cwrap('init_date', 'number', ['number']);
595
+ this._initTime = w.cwrap('init_time', 'number', ['number']);
596
+ this._initTimestamp = w.cwrap('init_timestamp', 'number', ['number']);
597
+ this._initSymbolStr = w.cwrap('init_symbol_str', 'number', ['string', 'number']);
598
+ this._initStringStr = w.cwrap('init_string_str', 'number', ['string', 'number']);
599
+
600
+ this._readB8 = w.cwrap('read_b8', 'number', ['number']);
601
+ this._readU8 = w.cwrap('read_u8', 'number', ['number']);
602
+ this._readC8 = w.cwrap('read_c8', 'number', ['number']);
603
+ this._readI16 = w.cwrap('read_i16', 'number', ['number']);
604
+ this._readI32 = w.cwrap('read_i32', 'number', ['number']);
605
+ this._readI64 = w.cwrap('read_i64', 'number', ['number']);
606
+ this._readF64 = w.cwrap('read_f64', 'number', ['number']);
607
+ this._readDate = w.cwrap('read_date', 'number', ['number']);
608
+ this._readTime = w.cwrap('read_time', 'number', ['number']);
609
+ this._readTimestamp = w.cwrap('read_timestamp', 'number', ['number']);
610
+ this._readSymbolId = w.cwrap('read_symbol_id', 'number', ['number']);
611
+ this._symbolToStr = w.cwrap('symbol_to_str', 'string', ['number']);
612
+
613
+ this._initVector = w.cwrap('init_vector', 'number', ['number', 'number']);
614
+ this._initList = w.cwrap('init_list', 'number', ['number']);
615
+ this._vecAtIdx = w.cwrap('vec_at_idx', 'number', ['number', 'number']);
616
+ this._atIdx = w.cwrap('at_idx', 'number', ['number', 'number']);
617
+ this._atObj = w.cwrap('at_obj', 'number', ['number', 'number']);
618
+ this._pushObj = w.cwrap('push_obj', 'number', ['number', 'number']);
619
+ this._insObj = w.cwrap('ins_obj', 'number', ['number', 'number', 'number']);
620
+
621
+ this._initDict = w.cwrap('init_dict', 'number', ['number', 'number']);
622
+ this._dictKeys = w.cwrap('dict_keys', 'number', ['number']);
623
+ this._dictVals = w.cwrap('dict_vals', 'number', ['number']);
624
+ this._dictGet = w.cwrap('dict_get', 'number', ['number', 'number']);
625
+
626
+ this._initTable = w.cwrap('init_table', 'number', ['number', 'number']);
627
+ this._tableKeys = w.cwrap('table_keys', 'number', ['number']);
628
+ this._tableVals = w.cwrap('table_vals', 'number', ['number']);
629
+ this._tableCol = w.cwrap('table_col', 'number', ['number', 'string', 'number']);
630
+ this._tableRow = w.cwrap('table_row', 'number', ['number', 'number']);
631
+ this._tableCount = w.cwrap('table_count', 'number', ['number']);
632
+
633
+ this._querySelect = w.cwrap('query_select', 'number', ['number']);
634
+ this._queryUpdate = w.cwrap('query_update', 'number', ['number']);
635
+ this._tableInsert = w.cwrap('table_insert', 'number', ['number', 'number']);
636
+ this._tableUpsert = w.cwrap('table_upsert', 'number', ['number', 'number', 'number']);
637
+
638
+ this._internSymbol = w.cwrap('intern_symbol', 'number', ['string', 'number']);
639
+ this._globalSet = w.cwrap('global_set', null, ['number', 'number']);
640
+ this._quoteObj = w.cwrap('quote_obj', 'number', ['number']);
641
+ this._getTypeName = w.cwrap('get_type_name', 'string', ['number']);
642
+ }
643
+
644
+ get version() { return this._versionStr(); }
645
+
646
+ eval(code, sourceName) {
647
+ const ptr = this._evalCmd(code, sourceName || `eval:${++this._cmdCounter}`);
648
+ return this._wrapPtr(ptr);
649
+ }
650
+
651
+ format(obj) {
652
+ const ptr = obj instanceof RayObject ? obj._ptr : obj;
653
+ return this._strOfObj(ptr);
654
+ }
655
+
656
+ _wrapPtr(ptr) {
657
+ if (ptr === 0) return new RayNull(this, 0);
658
+
659
+ const type = this._getObjType(ptr);
660
+ const isAtom = this._isObjAtom(ptr);
661
+ const absType = type < 0 ? -type : type;
662
+
663
+ if (type === Types.ERR) return new RayError(this, ptr);
664
+ if (type === Types.NULL || this._isObjNull(ptr)) return new RayNull(this, ptr);
665
+
666
+ if (isAtom) {
667
+ switch (absType) {
668
+ case Types.B8: return new B8(this, ptr);
669
+ case Types.U8: return new U8(this, ptr);
670
+ case Types.C8: return new C8(this, ptr);
671
+ case Types.I16: return new I16(this, ptr);
672
+ case Types.I32: return new I32(this, ptr);
673
+ case Types.I64: return new I64(this, ptr);
674
+ case Types.F64: return new F64(this, ptr);
675
+ case Types.DATE: return new RayDate(this, ptr);
676
+ case Types.TIME: return new RayTime(this, ptr);
677
+ case Types.TIMESTAMP: return new RayTimestamp(this, ptr);
678
+ case Types.SYMBOL: return new RaySymbol(this, ptr);
679
+ case Types.GUID: return new GUID(this, ptr);
680
+ default: return new RayObject(this, ptr);
681
+ }
682
+ }
683
+
684
+ switch (type) {
685
+ case Types.C8: return new RayString(this, ptr);
686
+ case Types.LIST: return new List(this, ptr);
687
+ case Types.DICT: return new Dict(this, ptr);
688
+ case Types.TABLE: return new Table(this, ptr);
689
+ case Types.LAMBDA: return new Lambda(this, ptr);
690
+ default:
691
+ if (TYPED_ARRAY_MAP[type]) return new Vector(this, ptr, type);
692
+ return new RayObject(this, ptr);
693
+ }
694
+ }
695
+
696
+ // Constructors
697
+ b8(value) { return new B8(this, this._initB8(value ? 1 : 0)); }
698
+ u8(value) { return new U8(this, this._initU8(value & 0xFF)); }
699
+ c8(value) { return new C8(this, this._initC8(value.charCodeAt(0))); }
700
+ i16(value) { return new I16(this, this._initI16(value | 0)); }
701
+ i32(value) { return new I32(this, this._initI32(value | 0)); }
702
+ i64(value) { return new I64(this, this._initI64(Number(value))); }
703
+ f64(value) { return new F64(this, this._initF64(value)); }
704
+
705
+ date(value) {
706
+ let days;
707
+ if (value instanceof Date) {
708
+ const epoch = new Date(2000, 0, 1);
709
+ days = Math.floor((value - epoch) / (1000 * 60 * 60 * 24));
710
+ } else {
711
+ days = value | 0;
712
+ }
713
+ return new RayDate(this, this._initDate(days));
714
+ }
715
+
716
+ time(value) {
717
+ let ms;
718
+ if (value instanceof Date) {
719
+ ms = value.getHours() * 3600000 + value.getMinutes() * 60000 +
720
+ value.getSeconds() * 1000 + value.getMilliseconds();
721
+ } else {
722
+ ms = value | 0;
723
+ }
724
+ return new RayTime(this, this._initTime(ms));
725
+ }
726
+
727
+ timestamp(value) {
728
+ let ns;
729
+ if (value instanceof Date) {
730
+ const epoch = new Date(2000, 0, 1);
731
+ ns = Number(value - epoch) * 1000000;
732
+ } else {
733
+ ns = Number(value);
734
+ }
735
+ return new RayTimestamp(this, this._initTimestamp(ns));
736
+ }
737
+
738
+ symbol(value) { return new RaySymbol(this, this._initSymbolStr(value, value.length)); }
739
+ string(value) { return new RayString(this, this._initStringStr(value, value.length)); }
740
+
741
+ vector(type, lengthOrData) {
742
+ if (Array.isArray(lengthOrData)) {
743
+ const arr = lengthOrData;
744
+ const vec = new Vector(this, this._initVector(type, arr.length), type);
745
+ const view = vec.typedArray;
746
+ for (let i = 0; i < arr.length; i++) {
747
+ if (type === Types.I64 || type === Types.TIMESTAMP || type === Types.SYMBOL) {
748
+ view[i] = BigInt(arr[i]);
749
+ } else {
750
+ view[i] = arr[i];
751
+ }
752
+ }
753
+ return vec;
754
+ }
755
+ return new Vector(this, this._initVector(type, lengthOrData), type);
756
+ }
757
+
758
+ list(items) {
759
+ const len = items ? items.length : 0;
760
+ const list = new List(this, this._initList(len));
761
+ if (items) {
762
+ for (let i = 0; i < items.length; i++) {
763
+ list.set(i, items[i]);
764
+ }
765
+ }
766
+ return list;
767
+ }
768
+
769
+ dict(obj) {
770
+ const keys = Object.keys(obj);
771
+ const keyVec = this.vector(Types.SYMBOL, keys.length);
772
+ const keyView = keyVec.typedArray;
773
+ for (let i = 0; i < keys.length; i++) {
774
+ keyView[i] = BigInt(this._internSymbol(keys[i], keys[i].length));
775
+ }
776
+ const valList = this.list(Object.values(obj).map(v => this._toRayObject(v)));
777
+ return new Dict(this, this._initDict(keyVec._ptr, valList._ptr));
778
+ }
779
+
780
+ table(columns) {
781
+ const colNames = Object.keys(columns);
782
+ const keyVec = this.vector(Types.SYMBOL, colNames.length);
783
+ const keyView = keyVec.typedArray;
784
+ for (let i = 0; i < colNames.length; i++) {
785
+ keyView[i] = BigInt(this._internSymbol(colNames[i], colNames[i].length));
786
+ }
787
+ const valList = this.list();
788
+ for (const name of colNames) {
789
+ valList.push(this._arrayToVector(columns[name]));
790
+ }
791
+ return new Table(this, this._initTable(keyVec._ptr, valList._ptr));
792
+ }
793
+
794
+ _arrayToVector(arr) {
795
+ if (arr.length === 0) return this.vector(Types.I64, 0);
796
+
797
+ const first = arr[0];
798
+ let type;
799
+
800
+ if (typeof first === 'boolean') type = Types.B8;
801
+ else if (typeof first === 'number') type = Number.isInteger(first) ? Types.I64 : Types.F64;
802
+ else if (typeof first === 'bigint') type = Types.I64;
803
+ else if (typeof first === 'string') type = Types.SYMBOL;
804
+ else if (first instanceof Date) type = Types.TIMESTAMP;
805
+ else return this.list(arr.map(v => this._toRayObject(v)));
806
+
807
+ const vec = this.vector(type, arr.length);
808
+ const view = vec.typedArray;
809
+
810
+ for (let i = 0; i < arr.length; i++) {
811
+ if (type === Types.SYMBOL) {
812
+ view[i] = BigInt(this._internSymbol(arr[i], arr[i].length));
813
+ } else if (type === Types.I64 || type === Types.TIMESTAMP) {
814
+ if (arr[i] instanceof Date) {
815
+ const epoch = new Date(2000, 0, 1);
816
+ view[i] = BigInt((arr[i] - epoch) * 1000000);
817
+ } else {
818
+ view[i] = BigInt(arr[i]);
819
+ }
820
+ } else if (type === Types.B8) {
821
+ view[i] = arr[i] ? 1 : 0;
822
+ } else {
823
+ view[i] = arr[i];
824
+ }
825
+ }
826
+
827
+ return vec;
828
+ }
829
+
830
+ _toRayObject(value) {
831
+ if (value instanceof RayObject) return value;
832
+ if (value === null || value === undefined) return new RayNull(this, 0);
833
+ if (typeof value === 'boolean') return this.b8(value);
834
+ if (typeof value === 'number') return Number.isInteger(value) ? this.i64(value) : this.f64(value);
835
+ if (typeof value === 'bigint') return this.i64(value);
836
+ if (typeof value === 'string') return this.symbol(value);
837
+ if (value instanceof Date) return this.timestamp(value);
838
+ if (Array.isArray(value)) return this._arrayToVector(value);
839
+ if (typeof value === 'object') return this.dict(value);
840
+ return new RayNull(this, 0);
841
+ }
842
+
843
+ set(name, value) {
844
+ const sym = this.symbol(name);
845
+ const val = value instanceof RayObject ? value : this._toRayObject(value);
846
+ this._globalSet(sym._ptr, val._ptr);
847
+ }
848
+
849
+ get(name) { return this.eval(name); }
850
+ typeName(typeCode) { return this._getTypeName(typeCode); }
851
+
852
+ col(name) { return Expr.col(this, name); }
853
+ }
854
+
855
+ // ============================================================================
856
+ // Initialization Function
857
+ // ============================================================================
858
+
859
+ let _sdkInstance = null;
860
+ let _initPromise = null;
861
+
862
+ async function init(options = {}) {
863
+ const { wasmPath = './rayforce.js', singleton = true, onReady = null } = options;
864
+
865
+ if (singleton && _sdkInstance !== null) return _sdkInstance;
866
+ if (singleton && _initPromise !== null) return _initPromise;
867
+
868
+ const initFn = async () => {
869
+ try {
870
+ // For browser usage, we need to load the WASM module
871
+ let createRayforce;
872
+
873
+ if (typeof window !== 'undefined') {
874
+ // Browser environment - expect global createRayforce or load via script
875
+ if (typeof window.createRayforce === 'function') {
876
+ createRayforce = window.createRayforce;
877
+ } else {
878
+ // Try dynamic import
879
+ const module = await import(wasmPath);
880
+ createRayforce = module.default;
881
+ }
882
+ } else {
883
+ // Node.js environment
884
+ const module = await import(wasmPath);
885
+ createRayforce = module.default;
886
+ }
887
+
888
+ const wasm = await createRayforce({
889
+ rayforce_ready: (msg) => { if (onReady) onReady(msg); }
890
+ });
891
+
892
+ const sdk = new RayforceSDK(wasm);
893
+ if (singleton) _sdkInstance = sdk;
894
+ return sdk;
895
+ } catch (error) {
896
+ if (singleton) _initPromise = null;
897
+ throw new Error(`Failed to initialize RayforceDB: ${error.message}`);
898
+ }
899
+ };
900
+
901
+ if (singleton) {
902
+ _initPromise = initFn();
903
+ return _initPromise;
904
+ }
905
+ return initFn();
906
+ }
907
+
908
+ function getInstance() { return _sdkInstance; }
909
+ function isInitialized() { return _sdkInstance !== null; }
910
+ function reset() { _sdkInstance = null; _initPromise = null; }
911
+
912
+ // ============================================================================
913
+ // Public API
914
+ // ============================================================================
915
+
916
+ return {
917
+ init,
918
+ getInstance,
919
+ isInitialized,
920
+ reset,
921
+ Types,
922
+ Expr,
923
+ RayforceSDK,
924
+ RayObject,
925
+ Vector,
926
+ List,
927
+ Dict,
928
+ Table,
929
+ RayString,
930
+ version: '0.1.0',
931
+ };
932
+
933
+ }));