@synnaxlabs/x 0.14.1 → 0.15.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/.turbo/turbo-build.log +5 -5
- package/dist/telem/generate.d.ts +2 -2
- package/dist/telem/series.d.ts +43 -19
- package/dist/telem/telem.d.ts +14 -9
- package/dist/x.cjs +9 -5
- package/dist/x.cjs.map +1 -1
- package/dist/x.js +2122 -1891
- package/dist/x.js.map +1 -1
- package/package.json +3 -3
- package/src/telem/generate.ts +2 -2
- package/src/telem/series.spec.ts +248 -4
- package/src/telem/series.ts +417 -76
- package/src/telem/telem.spec.ts +9 -0
- package/src/telem/telem.ts +56 -27
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@synnaxlabs/x",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.15.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Common Utilities for Synnax Labs",
|
|
7
7
|
"repository": "https://github.com/synnaxlabs/synnax/tree/main/x/go",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"eslint": "^8.55.0",
|
|
28
28
|
"vite": "^5.1.2",
|
|
29
29
|
"vitest": "^1.2.2",
|
|
30
|
+
"@synnaxlabs/vite-plugin": "0.0.1",
|
|
30
31
|
"eslint-config-synnaxlabs": "0.0.1",
|
|
31
|
-
"@synnaxlabs/tsconfig": "0.0.2"
|
|
32
|
-
"@synnaxlabs/vite-plugin": "0.0.1"
|
|
32
|
+
"@synnaxlabs/tsconfig": "0.0.2"
|
|
33
33
|
},
|
|
34
34
|
"main": "dist/x.cjs",
|
|
35
35
|
"module": "dist/x.js",
|
package/src/telem/generate.ts
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
// License, use of this software will be governed by the Apache License, Version 2.0,
|
|
8
8
|
// included in the file licenses/APL.txt.
|
|
9
9
|
|
|
10
|
-
import { DataType, DataTypeT,
|
|
10
|
+
import { DataType, type DataTypeT, type TypedArray } from "@/telem/telem";
|
|
11
11
|
|
|
12
|
-
export const randomSeries = (length: number, dataType: DataTypeT):
|
|
12
|
+
export const randomSeries = (length: number, dataType: DataTypeT): TypedArray => {
|
|
13
13
|
// generate random bytes of the correct length
|
|
14
14
|
const bytes = new Uint8Array(length * new DataType(dataType).density.valueOf());
|
|
15
15
|
for (let i = 0; i < bytes.byteLength; i++) {
|
package/src/telem/series.spec.ts
CHANGED
|
@@ -11,13 +11,37 @@ import { describe, expect, test, it } from "vitest";
|
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
13
|
import { MockGLBufferController } from "@/mock/MockGLBufferController";
|
|
14
|
-
import { Series } from "@/telem/series";
|
|
15
|
-
import { DataType, Rate, Size, TimeRange, TimeStamp } from "@/telem/telem";
|
|
14
|
+
import { Series, isCrudeSeries, MultiSeries } from "@/telem/series";
|
|
15
|
+
import { DataType, Rate, Size, TimeRange, TimeSpan, TimeStamp } from "@/telem/telem";
|
|
16
16
|
|
|
17
17
|
describe("Series", () => {
|
|
18
18
|
describe("construction", () => {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const IS_CRUDE_SERIES_SPEC: Array<[unknown, boolean]> = [
|
|
20
|
+
[{}, false],
|
|
21
|
+
[{ constructor: {} }, false],
|
|
22
|
+
[1, true],
|
|
23
|
+
[[1, 2, 3], true],
|
|
24
|
+
[["a", "b", "c"], true],
|
|
25
|
+
[new Float32Array([12]), true],
|
|
26
|
+
];
|
|
27
|
+
IS_CRUDE_SERIES_SPEC.forEach(([value, expected]) => {
|
|
28
|
+
it(`should return ${expected} for ${JSON.stringify(value)}`, () => {
|
|
29
|
+
expect(isCrudeSeries(value)).toEqual(expected);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test("from another series", () => {
|
|
34
|
+
const a = new Series({
|
|
35
|
+
data: new Float32Array([1, 2, 3]),
|
|
36
|
+
timeRange: new TimeRange(TimeStamp.seconds(5), TimeStamp.seconds(20)),
|
|
37
|
+
});
|
|
38
|
+
const b = new Series(a);
|
|
39
|
+
expect(b.buffer).toBe(a.buffer);
|
|
40
|
+
expect(b.timeRange).toBe(a.timeRange);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("valid from typed array", () => {
|
|
44
|
+
const a = new Series(new Float32Array([1, 2, 3]));
|
|
21
45
|
expect(a.dataType.toString()).toBe(DataType.FLOAT32.toString());
|
|
22
46
|
expect(a.length).toEqual(3);
|
|
23
47
|
expect(a.byteLength).toEqual(Size.bytes(12));
|
|
@@ -39,6 +63,74 @@ describe("Series", () => {
|
|
|
39
63
|
}).toThrow();
|
|
40
64
|
});
|
|
41
65
|
|
|
66
|
+
test("valid from js array", () => {
|
|
67
|
+
const a = new Series({ data: [1, 2, 3], dataType: DataType.FLOAT32 });
|
|
68
|
+
expect(a.dataType.toString()).toBe(DataType.FLOAT32.toString());
|
|
69
|
+
expect(a.length).toEqual(3);
|
|
70
|
+
expect(a.byteLength).toEqual(Size.bytes(12));
|
|
71
|
+
expect(a.byteCapacity).toEqual(Size.bytes(12));
|
|
72
|
+
expect(a.capacity).toEqual(3);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should assume float64 when JS numbers are passed as data", () => {
|
|
76
|
+
const s = new Series({ data: [1, 2, 3] });
|
|
77
|
+
expect(s.dataType.equals(DataType.FLOAT64));
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it("should assume float64 when a single number is passed in", () => {
|
|
81
|
+
const s = new Series(1);
|
|
82
|
+
expect(s.dataType.equals(DataType.FLOAT64)).toBeTruthy();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("should assume string when JS strings are passed as data", () => {
|
|
86
|
+
const s = new Series({ data: ["apple", "banana", "carrot"] });
|
|
87
|
+
expect(s.dataType.equals(DataType.STRING));
|
|
88
|
+
expect(s.length).toEqual(3);
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it("should assume string when a single string is passed as data", () => {
|
|
92
|
+
const s = new Series("abc");
|
|
93
|
+
expect(s.dataType.equals(DataType.STRING)).toBeTruthy();
|
|
94
|
+
expect(s.length).toEqual(1);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("should assume JSON when JS objects are passed as data", () => {
|
|
98
|
+
const s = new Series({ data: [{ a: 1, b: "apple" }] });
|
|
99
|
+
expect(s.dataType.equals(DataType.JSON));
|
|
100
|
+
expect(s.length).toEqual(1);
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("should correctly interpret a bigint as an int64", () => {
|
|
104
|
+
const s = new Series(1n);
|
|
105
|
+
expect(s.dataType.equals(DataType.INT64)).toBeTruthy();
|
|
106
|
+
expect(s.length).toEqual(1);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("should correctly interpret a TimeStamp object as a data type of timestamp", () => {
|
|
110
|
+
const s = new Series(TimeStamp.now());
|
|
111
|
+
expect(s.dataType).toEqual(DataType.TIMESTAMP);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("should correctly interpret an array of TimeStamps as a data type of timestamp", () => {
|
|
115
|
+
const s = new Series([TimeStamp.now(), TimeStamp.now().add(TimeSpan.seconds(1))]);
|
|
116
|
+
expect(s.dataType).toEqual(DataType.TIMESTAMP);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("should correctly interpret a Date object as a data type of timestamp", () => {
|
|
120
|
+
const s = new Series(new Date());
|
|
121
|
+
expect(s.dataType).toEqual(DataType.TIMESTAMP);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should encode objects as JSON", () => {
|
|
125
|
+
const a = new Series({ data: [{ a: 1, b: "apple" }], dataType: DataType.JSON });
|
|
126
|
+
expect(a.dataType.toString()).toBe(DataType.JSON.toString());
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should correctly separate strings", () => {
|
|
130
|
+
const a = new Series({ data: ["apple"], dataType: DataType.STRING });
|
|
131
|
+
expect(a.dataType.toString()).toBe(DataType.STRING.toString());
|
|
132
|
+
});
|
|
133
|
+
|
|
42
134
|
test("from buffer with data type provided", () => {
|
|
43
135
|
const a = new Series({ data: new ArrayBuffer(4), dataType: DataType.FLOAT32 });
|
|
44
136
|
expect(a.dataType.toString()).toBe(DataType.FLOAT32.toString());
|
|
@@ -103,6 +195,48 @@ describe("Series", () => {
|
|
|
103
195
|
series.at(3, true);
|
|
104
196
|
}).toThrow();
|
|
105
197
|
});
|
|
198
|
+
it("should return the correct value for a string series", () => {
|
|
199
|
+
const series = new Series({
|
|
200
|
+
data: ["apple", "banana", "carrot"],
|
|
201
|
+
dataType: DataType.STRING,
|
|
202
|
+
});
|
|
203
|
+
expect(series.at(0)).toEqual("apple");
|
|
204
|
+
expect(series.at(1)).toEqual("banana");
|
|
205
|
+
expect(series.at(2)).toEqual("carrot");
|
|
206
|
+
expect(series.at(-1)).toEqual("carrot");
|
|
207
|
+
});
|
|
208
|
+
it("should return the correct value for a JSON series", () => {
|
|
209
|
+
const series = new Series({
|
|
210
|
+
data: [
|
|
211
|
+
{ a: 1, b: "apple" },
|
|
212
|
+
{ a: 2, b: "banana" },
|
|
213
|
+
],
|
|
214
|
+
dataType: DataType.JSON,
|
|
215
|
+
});
|
|
216
|
+
expect(series.at(0)).toEqual({ a: 1, b: "apple" });
|
|
217
|
+
expect(series.at(1)).toEqual({ a: 2, b: "banana" });
|
|
218
|
+
});
|
|
219
|
+
it("should throw an error if the index is out of bounds for a string series", () => {
|
|
220
|
+
const series = new Series({
|
|
221
|
+
data: ["apple", "banana", "carrot"],
|
|
222
|
+
dataType: DataType.STRING,
|
|
223
|
+
});
|
|
224
|
+
expect(() => {
|
|
225
|
+
series.at(3, true);
|
|
226
|
+
}).toThrow();
|
|
227
|
+
});
|
|
228
|
+
it("should throw an error if the index is out of bounds for a JSON series", () => {
|
|
229
|
+
const series = new Series({
|
|
230
|
+
data: [
|
|
231
|
+
{ a: 1, b: "apple" },
|
|
232
|
+
{ a: 2, b: "banana" },
|
|
233
|
+
],
|
|
234
|
+
dataType: DataType.JSON,
|
|
235
|
+
});
|
|
236
|
+
expect(() => {
|
|
237
|
+
series.at(2, true);
|
|
238
|
+
}).toThrow();
|
|
239
|
+
});
|
|
106
240
|
});
|
|
107
241
|
|
|
108
242
|
describe("slice", () => {
|
|
@@ -135,6 +269,11 @@ describe("Series", () => {
|
|
|
135
269
|
expect(series.max).toEqual(3);
|
|
136
270
|
expect(series.min).toEqual(1);
|
|
137
271
|
});
|
|
272
|
+
it("should throw an error if that data type is not numeric", () => {
|
|
273
|
+
const series = new Series({ data: ["a", "b", "c"] });
|
|
274
|
+
expect(() => series.max == null).toThrow();
|
|
275
|
+
expect(() => series.min == null).toThrow();
|
|
276
|
+
});
|
|
138
277
|
});
|
|
139
278
|
|
|
140
279
|
describe("conversion", () => {
|
|
@@ -364,4 +503,109 @@ describe("Series", () => {
|
|
|
364
503
|
expect(series.binarySearch(6)).toEqual(5);
|
|
365
504
|
});
|
|
366
505
|
});
|
|
506
|
+
|
|
507
|
+
describe("array construction", () => {
|
|
508
|
+
it("should correctly a JS array from a series", () => {
|
|
509
|
+
const s = new Series([1, 2, 3]);
|
|
510
|
+
const arr = Array.from(s);
|
|
511
|
+
expect(arr).toEqual([1, 2, 3]);
|
|
512
|
+
});
|
|
513
|
+
it("should correctly construct a js array from a string series", () => {
|
|
514
|
+
const s = new Series(["apple", "banana", "carrot"]);
|
|
515
|
+
const arr = Array.from(s);
|
|
516
|
+
expect(arr).toEqual(["apple", "banana", "carrot"]);
|
|
517
|
+
});
|
|
518
|
+
it("should correctly construct a JS array from a JSON series", () => {
|
|
519
|
+
const s = new Series([
|
|
520
|
+
{ a: 1, b: "apple" },
|
|
521
|
+
{ a: 2, b: "banana" },
|
|
522
|
+
{ a: 3, b: "carrot" },
|
|
523
|
+
]);
|
|
524
|
+
const arr = Array.from(s);
|
|
525
|
+
expect(arr).toEqual([
|
|
526
|
+
{ a: 1, b: "apple" },
|
|
527
|
+
{ a: 2, b: "banana" },
|
|
528
|
+
{ a: 3, b: "carrot" },
|
|
529
|
+
]);
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
});
|
|
533
|
+
|
|
534
|
+
describe("MultiSeries", () => {
|
|
535
|
+
describe("length", () => {
|
|
536
|
+
it("should correctly return the length of the multi-series", () => {
|
|
537
|
+
const a = new Series(new Float32Array([1, 2, 3]));
|
|
538
|
+
const b = new Series(new Float32Array([4, 5, 6]));
|
|
539
|
+
const multi = new MultiSeries([a, b]);
|
|
540
|
+
expect(multi.length).toEqual(6);
|
|
541
|
+
});
|
|
542
|
+
});
|
|
543
|
+
describe("at", () => {
|
|
544
|
+
it("should correctly return the value at a particular index", () => {
|
|
545
|
+
const a = new Series(new Float32Array([1, 2, 3]));
|
|
546
|
+
const b = new Series(new Float32Array([4, 5, 6]));
|
|
547
|
+
const multi = new MultiSeries([a, b]);
|
|
548
|
+
expect(multi.at(0)).toEqual(1);
|
|
549
|
+
expect(multi.at(1)).toEqual(2);
|
|
550
|
+
expect(multi.at(2)).toEqual(3);
|
|
551
|
+
expect(multi.at(3)).toEqual(4);
|
|
552
|
+
expect(multi.at(4)).toEqual(5);
|
|
553
|
+
expect(multi.at(5)).toEqual(6);
|
|
554
|
+
});
|
|
555
|
+
it("should correctly return a value via negative indexing", () => {
|
|
556
|
+
const a = new Series(new Float32Array([1, 2, 3]));
|
|
557
|
+
const b = new Series(new Float32Array([4, 5, 6]));
|
|
558
|
+
const multi = new MultiSeries([a, b]);
|
|
559
|
+
expect(multi.at(-1)).toEqual(6);
|
|
560
|
+
expect(multi.at(-2)).toEqual(5);
|
|
561
|
+
expect(multi.at(-3)).toEqual(4);
|
|
562
|
+
expect(multi.at(-4)).toEqual(3);
|
|
563
|
+
expect(multi.at(-5)).toEqual(2);
|
|
564
|
+
expect(multi.at(-6)).toEqual(1);
|
|
565
|
+
});
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
describe("array construction", () => {
|
|
569
|
+
it("should correctly construct a JS array from a multi-series", () => {
|
|
570
|
+
const a = new Series(new Float32Array([1, 2, 3]));
|
|
571
|
+
const b = new Series(new Float32Array([4, 5, 6]));
|
|
572
|
+
const multi = new MultiSeries([a, b]);
|
|
573
|
+
const arr = Array.from(multi);
|
|
574
|
+
expect(arr).toEqual([1, 2, 3, 4, 5, 6]);
|
|
575
|
+
});
|
|
576
|
+
it("should correctly construct a JS array from a multi-series of strings", () => {
|
|
577
|
+
const a = new Series(["apple", "banana", "carrot"]);
|
|
578
|
+
const b = new Series(["dog", "elephant", "fox"]);
|
|
579
|
+
const multi = new MultiSeries([a, b]);
|
|
580
|
+
const arr = Array.from(multi);
|
|
581
|
+
expect(arr).toEqual(["apple", "banana", "carrot", "dog", "elephant", "fox"]);
|
|
582
|
+
});
|
|
583
|
+
it("should correctly construct a JS array from a multi-series of JSON", () => {
|
|
584
|
+
const a = new Series([
|
|
585
|
+
{ a: 1, b: "apple" },
|
|
586
|
+
{ a: 2, b: "banana" },
|
|
587
|
+
{ a: 3, b: "carrot" },
|
|
588
|
+
]);
|
|
589
|
+
const b = new Series([
|
|
590
|
+
{ a: 4, b: "dog" },
|
|
591
|
+
{ a: 5, b: "elephant" },
|
|
592
|
+
{ a: 6, b: "fox" },
|
|
593
|
+
]);
|
|
594
|
+
const multi = new MultiSeries([a, b]);
|
|
595
|
+
const arr = Array.from(multi);
|
|
596
|
+
expect(arr).toEqual([
|
|
597
|
+
{ a: 1, b: "apple" },
|
|
598
|
+
{ a: 2, b: "banana" },
|
|
599
|
+
{ a: 3, b: "carrot" },
|
|
600
|
+
{ a: 4, b: "dog" },
|
|
601
|
+
{ a: 5, b: "elephant" },
|
|
602
|
+
{ a: 6, b: "fox" },
|
|
603
|
+
]);
|
|
604
|
+
});
|
|
605
|
+
it("should correctly construct a JS array from a multi-series with no series", () => {
|
|
606
|
+
const multi = new MultiSeries([]);
|
|
607
|
+
const arr = Array.from(multi);
|
|
608
|
+
expect(arr).toEqual([]);
|
|
609
|
+
});
|
|
610
|
+
});
|
|
367
611
|
});
|