@milaboratories/pl-model-common 1.11.4 → 1.13.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/dist/drivers/pframe/data_info.d.ts +169 -0
- package/dist/drivers/pframe/data_info.d.ts.map +1 -0
- package/dist/drivers/pframe/{data.d.ts → data_types.d.ts} +1 -7
- package/dist/drivers/pframe/data_types.d.ts.map +1 -0
- package/dist/drivers/pframe/driver.d.ts +1 -1
- package/dist/drivers/pframe/driver.d.ts.map +1 -1
- package/dist/drivers/pframe/index.d.ts +2 -1
- package/dist/drivers/pframe/index.d.ts.map +1 -1
- package/dist/drivers/pframe/spec/{anchored_id.d.ts → anchored.d.ts} +20 -13
- package/dist/drivers/pframe/spec/anchored.d.ts.map +1 -0
- package/dist/drivers/pframe/spec/filtered_column.d.ts +31 -0
- package/dist/drivers/pframe/spec/filtered_column.d.ts.map +1 -0
- package/dist/drivers/pframe/spec/ids.d.ts +24 -0
- package/dist/drivers/pframe/spec/ids.d.ts.map +1 -0
- package/dist/drivers/pframe/spec/index.d.ts +3 -1
- package/dist/drivers/pframe/spec/index.d.ts.map +1 -1
- package/dist/drivers/pframe/spec/selectors.d.ts +3 -3
- package/dist/drivers/pframe/spec/selectors.d.ts.map +1 -1
- package/dist/drivers/pframe/spec/spec.d.ts +2 -0
- package/dist/drivers/pframe/spec/spec.d.ts.map +1 -1
- package/dist/drivers/pframe/table.d.ts +1 -1
- package/dist/drivers/pframe/table.d.ts.map +1 -1
- package/dist/drivers/pframe/table_calculate.d.ts +1 -1
- package/dist/drivers/pframe/table_calculate.d.ts.map +1 -1
- package/dist/drivers/pframe/unique_values.d.ts +1 -1
- package/dist/drivers/pframe/unique_values.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +383 -191
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/drivers/pframe/data_info.ts +430 -0
- package/src/drivers/pframe/{data.ts → data_types.ts} +0 -7
- package/src/drivers/pframe/driver.ts +1 -1
- package/src/drivers/pframe/index.ts +2 -1
- package/src/drivers/pframe/spec/{anchored_id.ts → anchored.ts} +63 -21
- package/src/drivers/pframe/spec/filtered_column.ts +39 -0
- package/src/drivers/pframe/spec/ids.ts +31 -0
- package/src/drivers/pframe/spec/index.ts +3 -1
- package/src/drivers/pframe/spec/selectors.ts +4 -3
- package/src/drivers/pframe/spec/spec.ts +6 -0
- package/src/drivers/pframe/table.ts +1 -1
- package/src/drivers/pframe/table_calculate.ts +1 -1
- package/src/drivers/pframe/unique_values.ts +1 -1
- package/dist/drivers/pframe/data.d.ts.map +0 -1
- package/dist/drivers/pframe/spec/anchored_id.d.ts.map +0 -1
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents a JavaScript representation of a value in a PColumn. Can be null, a number, or a string.
|
|
3
|
+
* These are the primitive types that can be stored directly in PColumns.
|
|
4
|
+
*
|
|
5
|
+
* Note: Actual columns can hold more value types, which are converted to these JavaScript types
|
|
6
|
+
* once they enter the JavaScript runtime.
|
|
7
|
+
*/
|
|
8
|
+
export type PColumnValue = null | number | string;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents a key for a PColumn value.
|
|
12
|
+
* Can be an array of strings or numbers.
|
|
13
|
+
*/
|
|
14
|
+
export type PColumnKey = (number | string)[];
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Represents a single entry in a PColumn's data structure.
|
|
18
|
+
* Contains a key and a value.
|
|
19
|
+
*/
|
|
20
|
+
export type PColumnDataEntry<T> = {
|
|
21
|
+
/** Key for the value */
|
|
22
|
+
key: PColumnKey;
|
|
23
|
+
|
|
24
|
+
/** Value / blob at the given key */
|
|
25
|
+
value: T;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Represents column data stored as a simple JSON structure.
|
|
30
|
+
* Used for small datasets that can be efficiently stored directly in memory.
|
|
31
|
+
*/
|
|
32
|
+
export type JsonDataInfo = {
|
|
33
|
+
/** Identifier for this data format ('Json') */
|
|
34
|
+
type: 'Json';
|
|
35
|
+
|
|
36
|
+
/** Number of axes that make up the complete key (tuple length) */
|
|
37
|
+
keyLength: number;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Key-value pairs where keys are stringified tuples of axis values
|
|
41
|
+
* and values are the column values for those coordinates
|
|
42
|
+
*/
|
|
43
|
+
data: Record<string, PColumnValue>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Represents column data partitioned across multiple JSON blobs.
|
|
48
|
+
* Used for larger datasets that need to be split into manageable chunks.
|
|
49
|
+
*/
|
|
50
|
+
export type JsonPartitionedDataInfo<Blob> = {
|
|
51
|
+
/** Identifier for this data format ('JsonPartitioned') */
|
|
52
|
+
type: 'JsonPartitioned';
|
|
53
|
+
|
|
54
|
+
/** Number of leading axes used for partitioning */
|
|
55
|
+
partitionKeyLength: number;
|
|
56
|
+
|
|
57
|
+
/** Map of stringified partition keys to blob references */
|
|
58
|
+
parts: Record<string, Blob>;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Represents a binary format chunk containing index and values as separate blobs.
|
|
63
|
+
* Used for efficient storage and retrieval of column data in binary format.
|
|
64
|
+
*/
|
|
65
|
+
export type BinaryChunk<Blob> = {
|
|
66
|
+
/** Binary blob containing structured index information */
|
|
67
|
+
index: Blob;
|
|
68
|
+
|
|
69
|
+
/** Binary blob containing the actual values */
|
|
70
|
+
values: Blob;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Represents column data partitioned across multiple binary chunks.
|
|
75
|
+
* Optimized for efficient storage and retrieval of large datasets.
|
|
76
|
+
*/
|
|
77
|
+
export type BinaryPartitionedDataInfo<Blob> = {
|
|
78
|
+
/** Identifier for this data format ('BinaryPartitioned') */
|
|
79
|
+
type: 'BinaryPartitioned';
|
|
80
|
+
|
|
81
|
+
/** Number of leading axes used for partitioning */
|
|
82
|
+
partitionKeyLength: number;
|
|
83
|
+
|
|
84
|
+
/** Map of stringified partition keys to binary chunks */
|
|
85
|
+
parts: Record<string, BinaryChunk<Blob>>;
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Union type representing all possible data storage formats for PColumn data.
|
|
90
|
+
* The specific format used depends on data size, access patterns, and performance requirements.
|
|
91
|
+
*
|
|
92
|
+
* @template Blob - Type parameter representing the storage reference type (could be ResourceInfo, PFrameBlobId, etc.)
|
|
93
|
+
*/
|
|
94
|
+
export type DataInfo<Blob> =
|
|
95
|
+
| JsonDataInfo
|
|
96
|
+
| JsonPartitionedDataInfo<Blob>
|
|
97
|
+
| BinaryPartitionedDataInfo<Blob>;
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Type guard function that checks if the given value is a valid DataInfo.
|
|
101
|
+
*
|
|
102
|
+
* @param value - The value to check
|
|
103
|
+
* @returns True if the value is a valid DataInfo, false otherwise
|
|
104
|
+
*/
|
|
105
|
+
export function isDataInfo<Blob>(value: unknown): value is DataInfo<Blob> {
|
|
106
|
+
if (!value || typeof value !== 'object') {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const data = value as Record<string, unknown>;
|
|
111
|
+
if (!('type' in data)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
switch (data.type) {
|
|
116
|
+
case 'Json':
|
|
117
|
+
return (
|
|
118
|
+
typeof data.keyLength === 'number'
|
|
119
|
+
&& data.data !== undefined
|
|
120
|
+
&& typeof data.data === 'object'
|
|
121
|
+
);
|
|
122
|
+
case 'JsonPartitioned':
|
|
123
|
+
return (
|
|
124
|
+
typeof data.partitionKeyLength === 'number'
|
|
125
|
+
&& data.parts !== undefined
|
|
126
|
+
&& typeof data.parts === 'object'
|
|
127
|
+
);
|
|
128
|
+
case 'BinaryPartitioned':
|
|
129
|
+
return (
|
|
130
|
+
typeof data.partitionKeyLength === 'number'
|
|
131
|
+
&& data.parts !== undefined
|
|
132
|
+
&& typeof data.parts === 'object'
|
|
133
|
+
);
|
|
134
|
+
default:
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Maps blob references in a DataInfo object from one type to another using a mapping function.
|
|
141
|
+
*
|
|
142
|
+
* @template B1 - Source blob type
|
|
143
|
+
* @template B2 - Target blob type
|
|
144
|
+
* @param dataInfo - The source DataInfo object
|
|
145
|
+
* @param mapFn - Function to transform blobs from type B1 to type B2
|
|
146
|
+
* @returns A new DataInfo object with transformed blob references
|
|
147
|
+
*/
|
|
148
|
+
export function mapDataInfo<B1, B2>(
|
|
149
|
+
dataInfo: DataInfo<B1>,
|
|
150
|
+
mapFn: (blob: B1) => B2,
|
|
151
|
+
): DataInfo<B2>;
|
|
152
|
+
export function mapDataInfo<B1, B2>(
|
|
153
|
+
dataInfo: DataInfo<B1> | undefined,
|
|
154
|
+
mapFn: (blob: B1) => B2,
|
|
155
|
+
): DataInfo<B2> | undefined {
|
|
156
|
+
if (dataInfo === undefined) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
switch (dataInfo.type) {
|
|
161
|
+
case 'Json':
|
|
162
|
+
// Json type doesn't contain blobs, so return as is
|
|
163
|
+
return dataInfo;
|
|
164
|
+
case 'JsonPartitioned': {
|
|
165
|
+
// Map each blob in parts
|
|
166
|
+
const newParts: Record<string, B2> = {};
|
|
167
|
+
for (const [key, blob] of Object.entries(dataInfo.parts)) {
|
|
168
|
+
newParts[key] = mapFn(blob);
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
...dataInfo,
|
|
172
|
+
parts: newParts,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
case 'BinaryPartitioned': {
|
|
176
|
+
// Map each index and values blob in parts
|
|
177
|
+
const newParts: Record<string, BinaryChunk<B2>> = {};
|
|
178
|
+
for (const [key, chunk] of Object.entries(dataInfo.parts)) {
|
|
179
|
+
newParts[key] = {
|
|
180
|
+
index: mapFn(chunk.index),
|
|
181
|
+
values: mapFn(chunk.values),
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
...dataInfo,
|
|
186
|
+
parts: newParts,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
//
|
|
193
|
+
// Lightway representation for ExplicitJsonData
|
|
194
|
+
//
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Represents a single key-value entry in a column's explicit data structure.
|
|
198
|
+
* Used when directly instantiating PColumns with explicit data.
|
|
199
|
+
*/
|
|
200
|
+
export type PColumnValuesEntry = {
|
|
201
|
+
key: PColumnKey;
|
|
202
|
+
val: PColumnValue;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Array of key-value entries representing explicit column data.
|
|
207
|
+
* Used for lightweight explicit instantiation of PColumns.
|
|
208
|
+
*/
|
|
209
|
+
export type PColumnValues = PColumnValuesEntry[];
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Entry-based representation of JsonDataInfo
|
|
213
|
+
*/
|
|
214
|
+
export interface JsonDataInfoEntries {
|
|
215
|
+
type: 'Json';
|
|
216
|
+
keyLength: number;
|
|
217
|
+
data: PColumnDataEntry<PColumnValue>[];
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Entry-based representation of JsonPartitionedDataInfo
|
|
222
|
+
*/
|
|
223
|
+
export interface JsonPartitionedDataInfoEntries<Blob> {
|
|
224
|
+
type: 'JsonPartitioned';
|
|
225
|
+
partitionKeyLength: number;
|
|
226
|
+
parts: PColumnDataEntry<Blob>[];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Entry-based representation of BinaryPartitionedDataInfo
|
|
231
|
+
*/
|
|
232
|
+
export interface BinaryPartitionedDataInfoEntries<Blob> {
|
|
233
|
+
type: 'BinaryPartitioned';
|
|
234
|
+
partitionKeyLength: number;
|
|
235
|
+
parts: PColumnDataEntry<BinaryChunk<Blob>>[];
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Union type representing all possible entry-based data storage formats
|
|
240
|
+
*/
|
|
241
|
+
export type DataInfoEntries<Blob> =
|
|
242
|
+
| JsonDataInfoEntries
|
|
243
|
+
| JsonPartitionedDataInfoEntries<Blob>
|
|
244
|
+
| BinaryPartitionedDataInfoEntries<Blob>;
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Type guard function that checks if the given value is a valid DataInfoEntries.
|
|
248
|
+
*
|
|
249
|
+
* @param value - The value to check
|
|
250
|
+
* @returns True if the value is a valid DataInfoEntries, false otherwise
|
|
251
|
+
*/
|
|
252
|
+
export function isDataInfoEntries<Blob>(value: unknown): value is DataInfoEntries<Blob> {
|
|
253
|
+
if (!value || typeof value !== 'object') {
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const data = value as Record<string, unknown>;
|
|
258
|
+
if (!('type' in data)) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
switch (data.type) {
|
|
263
|
+
case 'Json':
|
|
264
|
+
return (
|
|
265
|
+
typeof data.keyLength === 'number'
|
|
266
|
+
&& Array.isArray(data.data)
|
|
267
|
+
);
|
|
268
|
+
case 'JsonPartitioned':
|
|
269
|
+
return (
|
|
270
|
+
typeof data.partitionKeyLength === 'number'
|
|
271
|
+
&& Array.isArray(data.parts)
|
|
272
|
+
);
|
|
273
|
+
case 'BinaryPartitioned':
|
|
274
|
+
return (
|
|
275
|
+
typeof data.partitionKeyLength === 'number'
|
|
276
|
+
&& Array.isArray(data.parts)
|
|
277
|
+
);
|
|
278
|
+
default:
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Converts DataInfo to DataInfoEntries
|
|
285
|
+
*
|
|
286
|
+
* @param dataInfo - The record-based DataInfo object
|
|
287
|
+
* @returns The equivalent entry-based DataInfoEntries object
|
|
288
|
+
*/
|
|
289
|
+
export function dataInfoToEntries<Blob>(dataInfo: DataInfo<Blob>): DataInfoEntries<Blob> {
|
|
290
|
+
switch (dataInfo.type) {
|
|
291
|
+
case 'Json': {
|
|
292
|
+
const entries: PColumnDataEntry<PColumnValue>[] = Object.entries(dataInfo.data).map(([keyStr, value]) => {
|
|
293
|
+
const key = JSON.parse(keyStr) as PColumnKey;
|
|
294
|
+
return { key, value };
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
type: 'Json',
|
|
299
|
+
keyLength: dataInfo.keyLength,
|
|
300
|
+
data: entries,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
case 'JsonPartitioned': {
|
|
304
|
+
const parts: PColumnDataEntry<Blob>[] = Object.entries(dataInfo.parts).map(([keyStr, blob]) => {
|
|
305
|
+
const key = JSON.parse(keyStr) as PColumnKey;
|
|
306
|
+
return { key, value: blob };
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
return {
|
|
310
|
+
type: 'JsonPartitioned',
|
|
311
|
+
partitionKeyLength: dataInfo.partitionKeyLength,
|
|
312
|
+
parts,
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
case 'BinaryPartitioned': {
|
|
316
|
+
const parts: PColumnDataEntry<BinaryChunk<Blob>>[] = Object.entries(dataInfo.parts).map(([keyStr, chunk]) => {
|
|
317
|
+
const key = JSON.parse(keyStr) as PColumnKey;
|
|
318
|
+
return { key, value: chunk };
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
type: 'BinaryPartitioned',
|
|
323
|
+
partitionKeyLength: dataInfo.partitionKeyLength,
|
|
324
|
+
parts,
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/**
|
|
331
|
+
* Converts DataInfoEntries to DataInfo
|
|
332
|
+
*
|
|
333
|
+
* @param dataInfoEntries - The entry-based DataInfoEntries object
|
|
334
|
+
* @returns The equivalent record-based DataInfo object
|
|
335
|
+
*/
|
|
336
|
+
export function entriesToDataInfo<Blob>(dataInfoEntries: DataInfoEntries<Blob>): DataInfo<Blob> {
|
|
337
|
+
switch (dataInfoEntries.type) {
|
|
338
|
+
case 'Json': {
|
|
339
|
+
const data: Record<string, PColumnValue> = {};
|
|
340
|
+
for (const entry of dataInfoEntries.data) {
|
|
341
|
+
data[JSON.stringify(entry.key)] = entry.value;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
type: 'Json',
|
|
346
|
+
keyLength: dataInfoEntries.keyLength,
|
|
347
|
+
data,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
case 'JsonPartitioned': {
|
|
351
|
+
const parts: Record<string, Blob> = {};
|
|
352
|
+
for (const entry of dataInfoEntries.parts) {
|
|
353
|
+
parts[JSON.stringify(entry.key)] = entry.value;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
return {
|
|
357
|
+
type: 'JsonPartitioned',
|
|
358
|
+
partitionKeyLength: dataInfoEntries.partitionKeyLength,
|
|
359
|
+
parts,
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
case 'BinaryPartitioned': {
|
|
363
|
+
const parts: Record<string, BinaryChunk<Blob>> = {};
|
|
364
|
+
for (const entry of dataInfoEntries.parts) {
|
|
365
|
+
parts[JSON.stringify(entry.key)] = entry.value;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
return {
|
|
369
|
+
type: 'BinaryPartitioned',
|
|
370
|
+
partitionKeyLength: dataInfoEntries.partitionKeyLength,
|
|
371
|
+
parts,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/**
|
|
378
|
+
* Maps blob references in a DataInfoEntries object from one type to another using a mapping function.
|
|
379
|
+
*
|
|
380
|
+
* @template B1 - Source blob type
|
|
381
|
+
* @template B2 - Target blob type
|
|
382
|
+
* @param dataInfoEntries - The source DataInfoEntries object
|
|
383
|
+
* @param mapFn - Function to transform blobs from type B1 to type B2
|
|
384
|
+
* @returns A new DataInfoEntries object with transformed blob references
|
|
385
|
+
*/
|
|
386
|
+
export function mapDataInfoEntries<B1, B2>(
|
|
387
|
+
dataInfoEntries: DataInfoEntries<B1>,
|
|
388
|
+
mapFn: (blob: B1) => B2,
|
|
389
|
+
): DataInfoEntries<B2>;
|
|
390
|
+
export function mapDataInfoEntries<B1, B2>(
|
|
391
|
+
dataInfoEntries: DataInfoEntries<B1> | undefined,
|
|
392
|
+
mapFn: (blob: B1) => B2,
|
|
393
|
+
): DataInfoEntries<B2> | undefined {
|
|
394
|
+
if (dataInfoEntries === undefined) {
|
|
395
|
+
return undefined;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
switch (dataInfoEntries.type) {
|
|
399
|
+
case 'Json':
|
|
400
|
+
// Json type doesn't contain blobs, so return as is
|
|
401
|
+
return dataInfoEntries;
|
|
402
|
+
case 'JsonPartitioned': {
|
|
403
|
+
// Map each blob in parts
|
|
404
|
+
const newParts = dataInfoEntries.parts.map((entry) => ({
|
|
405
|
+
key: entry.key,
|
|
406
|
+
value: mapFn(entry.value),
|
|
407
|
+
}));
|
|
408
|
+
|
|
409
|
+
return {
|
|
410
|
+
...dataInfoEntries,
|
|
411
|
+
parts: newParts,
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
case 'BinaryPartitioned': {
|
|
415
|
+
// Map each index and values blob in parts
|
|
416
|
+
const newParts = dataInfoEntries.parts.map((entry) => ({
|
|
417
|
+
key: entry.key,
|
|
418
|
+
value: {
|
|
419
|
+
index: mapFn(entry.value.index),
|
|
420
|
+
values: mapFn(entry.value.values),
|
|
421
|
+
},
|
|
422
|
+
}));
|
|
423
|
+
|
|
424
|
+
return {
|
|
425
|
+
...dataInfoEntries,
|
|
426
|
+
parts: newParts,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
@@ -242,13 +242,6 @@ export function isValueAbsent(absent: Uint8Array, index: number): boolean {
|
|
|
242
242
|
return (absent[chunkIndex] & mask) > 0;
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
-
export type PColumnValue = null | number | string;
|
|
246
|
-
export type PColumnValuesEntry = {
|
|
247
|
-
key: PColumnValue[];
|
|
248
|
-
val: PColumnValue;
|
|
249
|
-
};
|
|
250
|
-
export type PColumnValues = PColumnValuesEntry[];
|
|
251
|
-
|
|
252
245
|
export const PTableAbsent = { type: 'absent' };
|
|
253
246
|
export type PTableAbsent = typeof PTableAbsent;
|
|
254
247
|
export const PTableNA = null;
|
|
@@ -2,7 +2,7 @@ import type { Branded } from '../../branding';
|
|
|
2
2
|
import type { PTable } from './table';
|
|
3
3
|
import type { PFrame } from './pframe';
|
|
4
4
|
import type { AddParameterToAllMethods } from './type_util';
|
|
5
|
-
import type { PTableShape, PTableVector, TableRange } from './
|
|
5
|
+
import type { PTableShape, PTableVector, TableRange } from './data_types';
|
|
6
6
|
import type { FindColumnsRequest, FindColumnsResponse } from './find_columns';
|
|
7
7
|
import type { PObjectId } from '../../pool';
|
|
8
8
|
import type { PColumnIdAndSpec, PColumnSpec } from './spec/spec';
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import canonicalize from 'canonicalize';
|
|
2
2
|
import type { AxisId, PColumnSpec } from './spec';
|
|
3
3
|
import { getAxisId, matchAxisId } from './spec';
|
|
4
|
-
import type { AAxisSelector, AnchorAxisRef, AnchorAxisRefByIdx,
|
|
5
|
-
import type {
|
|
4
|
+
import type { AAxisSelector, AnchorAxisRef, AnchorAxisRefByIdx, AnchoredPColumnId, AnchoredPColumnSelector, AxisSelector, PColumnSelector } from './selectors';
|
|
5
|
+
import type { AxisFilter } from './filtered_column';
|
|
6
|
+
import type { PValue } from '../data_types';
|
|
7
|
+
import type { SUniversalPColumnId, UniversalPColumnId } from './ids';
|
|
8
|
+
import { stringifyColumnId } from './ids';
|
|
6
9
|
|
|
7
10
|
//
|
|
8
11
|
// Helper functions
|
|
@@ -16,18 +19,11 @@ function domainKey(key: string, value: string): string {
|
|
|
16
19
|
return JSON.stringify([key, value]);
|
|
17
20
|
}
|
|
18
21
|
|
|
19
|
-
//
|
|
20
|
-
// Branded types
|
|
21
|
-
//
|
|
22
|
-
|
|
23
|
-
/** Canonicalized string representation of an anchored column identifier, either anchored or absolute. */
|
|
24
|
-
export type CanonicalPColumnId = Branded<string, 'CanonicalPColumnId'>;
|
|
25
|
-
|
|
26
22
|
/**
|
|
27
23
|
* Context for resolving and generating anchored references to columns and axes
|
|
28
24
|
* Maintains maps of known domain values and axes that can be referenced by anchors
|
|
29
25
|
*/
|
|
30
|
-
export class
|
|
26
|
+
export class AnchoredIdDeriver {
|
|
31
27
|
private readonly domains = new Map<string, string>();
|
|
32
28
|
private readonly axes = new Map<string, AnchorAxisRefByIdx>();
|
|
33
29
|
/**
|
|
@@ -70,12 +66,24 @@ export class AnchorIdDeriver {
|
|
|
70
66
|
|
|
71
67
|
/**
|
|
72
68
|
* Derives an anchored column identifier from a column specification
|
|
73
|
-
* Replaces domain values and axes with anchored references when possible
|
|
74
69
|
* @param spec Column specification to anchor
|
|
75
70
|
* @returns An anchored column identifier that can be used to identify columns similar to the input specification
|
|
76
71
|
*/
|
|
77
|
-
derive(spec: PColumnSpec):
|
|
78
|
-
|
|
72
|
+
derive(spec: PColumnSpec): AnchoredPColumnId;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Derives an anchored column identifier from a column specification
|
|
76
|
+
* @param spec Column specification to anchor
|
|
77
|
+
* @param axisFilters Axis filters to apply to the column
|
|
78
|
+
* @returns An anchored and sliced column identifier that can be used to identify columns similar to the input specification
|
|
79
|
+
*/
|
|
80
|
+
derive(spec: PColumnSpec, axisFilters?: AxisFilter[]): UniversalPColumnId;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Implementation of derive method
|
|
84
|
+
*/
|
|
85
|
+
derive(spec: PColumnSpec, axisFilters?: AxisFilter[]): UniversalPColumnId {
|
|
86
|
+
const result: AnchoredPColumnId = {
|
|
79
87
|
name: spec.name,
|
|
80
88
|
axes: [],
|
|
81
89
|
};
|
|
@@ -116,28 +124,62 @@ export class AnchorIdDeriver {
|
|
|
116
124
|
return anchorAxisRef ?? axis;
|
|
117
125
|
});
|
|
118
126
|
|
|
119
|
-
return
|
|
127
|
+
// If no axis filters are provided, return the anchored ID as is
|
|
128
|
+
if (!axisFilters || axisFilters.length === 0) {
|
|
129
|
+
return result;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Process axis filters and create a sliced column ID
|
|
133
|
+
const resolvedFilters: [number, PValue][] = [];
|
|
134
|
+
|
|
135
|
+
for (const filter of axisFilters) {
|
|
136
|
+
const [axisIdOrIndex, value] = filter;
|
|
137
|
+
|
|
138
|
+
// If it's already a numeric index, validate it
|
|
139
|
+
if (typeof axisIdOrIndex === 'number') {
|
|
140
|
+
if (axisIdOrIndex < 0 || axisIdOrIndex >= spec.axesSpec.length) {
|
|
141
|
+
throw new Error(`Axis index ${axisIdOrIndex} is out of bounds (0-${spec.axesSpec.length - 1})`);
|
|
142
|
+
}
|
|
143
|
+
resolvedFilters.push([axisIdOrIndex, value]);
|
|
144
|
+
} else {
|
|
145
|
+
// If it's a string (axis name), resolve it to an index
|
|
146
|
+
const axisIndex = spec.axesSpec.findIndex((axis) => axis.name === axisIdOrIndex);
|
|
147
|
+
if (axisIndex === -1) {
|
|
148
|
+
throw new Error(`Axis with name "${axisIdOrIndex}" not found in the column specification`);
|
|
149
|
+
}
|
|
150
|
+
resolvedFilters.push([axisIndex, value]);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Sort filters by axis index to ensure consistency
|
|
155
|
+
resolvedFilters.sort((a, b) => a[0] - b[0]);
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
source: result,
|
|
159
|
+
axisFilters: resolvedFilters,
|
|
160
|
+
};
|
|
120
161
|
}
|
|
121
162
|
|
|
122
163
|
/**
|
|
123
164
|
* Derives a canonicalized string representation of an anchored column identifier, can be used as a unique identifier for the column
|
|
124
165
|
* @param spec Column specification to anchor
|
|
166
|
+
* @param axisFilters Optional axis filters to apply to the column
|
|
125
167
|
* @returns A canonicalized string representation of the anchored column identifier
|
|
126
168
|
*/
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
return canonicalize(aId)! as CanonicalPColumnId;
|
|
169
|
+
deriveS(spec: PColumnSpec, axisFilters?: AxisFilter[]): SUniversalPColumnId {
|
|
170
|
+
return stringifyColumnId(this.derive(spec, axisFilters));
|
|
130
171
|
}
|
|
131
172
|
}
|
|
132
173
|
|
|
133
174
|
/**
|
|
134
|
-
* Resolves anchored references in a column matcher to create a non-anchored matcher
|
|
175
|
+
* Resolves anchored references in a column matcher to create a non-anchored matcher.
|
|
176
|
+
* Doing an opposite operation to {@link AnchorIdDeriver.derive()}.
|
|
135
177
|
*
|
|
136
|
-
* @param anchors - Record of anchor column specifications indexed by anchor
|
|
137
|
-
* @param matcher - An anchored column matcher containing references that need to be resolved
|
|
178
|
+
* @param anchors - Record of anchor column specifications indexed by anchor id
|
|
179
|
+
* @param matcher - An anchored column matcher (or id, which is subtype of it) containing references that need to be resolved
|
|
138
180
|
* @returns A non-anchored column matcher with all references resolved to actual values
|
|
139
181
|
*/
|
|
140
|
-
export function resolveAnchors(anchors: Record<string, PColumnSpec>, matcher:
|
|
182
|
+
export function resolveAnchors(anchors: Record<string, PColumnSpec>, matcher: AnchoredPColumnSelector): PColumnSelector {
|
|
141
183
|
const result = { ...matcher };
|
|
142
184
|
|
|
143
185
|
if (result.domainAnchor !== undefined) {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { PValue } from '../data_types';
|
|
2
|
+
import type { AnchoredPColumnId } from './selectors';
|
|
3
|
+
|
|
4
|
+
/** Axis filter by index */
|
|
5
|
+
export type AxisFilterByIdx = [number, PValue];
|
|
6
|
+
|
|
7
|
+
/** Axis filter by name */
|
|
8
|
+
export type AxisFilterByName = [string, PValue];
|
|
9
|
+
|
|
10
|
+
/** Axis filter */
|
|
11
|
+
export type AxisFilter = AxisFilterByIdx | AxisFilterByName;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Identifies a column derived from a CanonicalPColumnId by fixing values on certain axes,
|
|
15
|
+
* thus effectively reducing the dimensionality of the original column.
|
|
16
|
+
*/
|
|
17
|
+
export type FilteredPColumn<CID = AnchoredPColumnId, AFI = AxisFilter> = {
|
|
18
|
+
/** The original column identifier */
|
|
19
|
+
source: CID;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* List of fixed axes and their corresponding values.
|
|
23
|
+
* Each entry fixes one axis to a specific value, creating a slice of the multidimensional data.
|
|
24
|
+
* This effectively reduces the dimensionality by one for each fixed axis.
|
|
25
|
+
* Ordered by the axis index in canonical case.
|
|
26
|
+
*/
|
|
27
|
+
axisFilters: AFI[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export type FilteredPColumnId = FilteredPColumn<AnchoredPColumnId, AxisFilterByIdx>;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Checks if a given value is a FilteredPColumn
|
|
34
|
+
* @param id - The value to check
|
|
35
|
+
* @returns True if the value is a FilteredPColumn, false otherwise
|
|
36
|
+
*/
|
|
37
|
+
export function isFilteredPColumn(id: unknown): id is FilteredPColumn {
|
|
38
|
+
return typeof id === 'object' && id !== null && 'source' in id && 'axisFilters' in id;
|
|
39
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Branded } from '../../../branding';
|
|
2
|
+
import type { AnchoredPColumnId } from './selectors';
|
|
3
|
+
import type { FilteredPColumnId } from './filtered_column';
|
|
4
|
+
import canonicalize from 'canonicalize';
|
|
5
|
+
/**
|
|
6
|
+
* Universal column identifier optionally anchored and optionally filtered.
|
|
7
|
+
*/
|
|
8
|
+
export type UniversalPColumnId = AnchoredPColumnId | FilteredPColumnId;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Canonically serialized {@link UniversalPColumnId}.
|
|
12
|
+
*/
|
|
13
|
+
export type SUniversalPColumnId = Branded<string, 'SUniversalPColumnId'>;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Canonically serializes a {@link UniversalPColumnId} to a string.
|
|
17
|
+
* @param id - The column identifier to serialize
|
|
18
|
+
* @returns The canonically serialized string
|
|
19
|
+
*/
|
|
20
|
+
export function stringifyColumnId(id: UniversalPColumnId): SUniversalPColumnId {
|
|
21
|
+
return canonicalize(id)! as SUniversalPColumnId;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Parses a canonically serialized {@link UniversalPColumnId} from a string.
|
|
26
|
+
* @param str - The string to parse
|
|
27
|
+
* @returns The parsed column identifier
|
|
28
|
+
*/
|
|
29
|
+
export function parseColumnId(str: SUniversalPColumnId): UniversalPColumnId {
|
|
30
|
+
return JSON.parse(str) as UniversalPColumnId;
|
|
31
|
+
}
|