@milaboratories/pf-driver 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +1 -0
  2. package/dist/__external/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.7.0_typescript@5.6.3/__external/tslib/tslib.es6.cjs +77 -0
  3. package/dist/__external/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.7.0_typescript@5.6.3/__external/tslib/tslib.es6.cjs.map +1 -0
  4. package/dist/__external/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.7.0_typescript@5.6.3/__external/tslib/tslib.es6.js +74 -0
  5. package/dist/__external/.pnpm/@rollup_plugin-typescript@12.1.4_rollup@4.52.4_tslib@2.7.0_typescript@5.6.3/__external/tslib/tslib.es6.js.map +1 -0
  6. package/dist/data_info_helpers.cjs +21 -0
  7. package/dist/data_info_helpers.cjs.map +1 -0
  8. package/dist/data_info_helpers.d.ts +3 -0
  9. package/dist/data_info_helpers.d.ts.map +1 -0
  10. package/dist/data_info_helpers.js +19 -0
  11. package/dist/data_info_helpers.js.map +1 -0
  12. package/dist/driver_decl.d.ts +38 -0
  13. package/dist/driver_decl.d.ts.map +1 -0
  14. package/dist/driver_double.cjs +98 -0
  15. package/dist/driver_double.cjs.map +1 -0
  16. package/dist/driver_double.d.ts +12 -0
  17. package/dist/driver_double.d.ts.map +1 -0
  18. package/dist/driver_double.js +95 -0
  19. package/dist/driver_double.js.map +1 -0
  20. package/dist/driver_impl.cjs +378 -0
  21. package/dist/driver_impl.cjs.map +1 -0
  22. package/dist/driver_impl.d.ts +54 -0
  23. package/dist/driver_impl.d.ts.map +1 -0
  24. package/dist/driver_impl.js +375 -0
  25. package/dist/driver_impl.js.map +1 -0
  26. package/dist/index.cjs +14 -0
  27. package/dist/index.cjs.map +1 -0
  28. package/dist/index.d.ts +5 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +4 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/logging.cjs +9 -0
  33. package/dist/logging.cjs.map +1 -0
  34. package/dist/logging.d.ts +2 -0
  35. package/dist/logging.d.ts.map +1 -0
  36. package/dist/logging.js +7 -0
  37. package/dist/logging.js.map +1 -0
  38. package/dist/pframe_pool.cjs +196 -0
  39. package/dist/pframe_pool.cjs.map +1 -0
  40. package/dist/pframe_pool.d.ts +35 -0
  41. package/dist/pframe_pool.d.ts.map +1 -0
  42. package/dist/pframe_pool.js +193 -0
  43. package/dist/pframe_pool.js.map +1 -0
  44. package/dist/ptable_cache_per_frame.cjs +69 -0
  45. package/dist/ptable_cache_per_frame.cjs.map +1 -0
  46. package/dist/ptable_cache_per_frame.d.ts +25 -0
  47. package/dist/ptable_cache_per_frame.d.ts.map +1 -0
  48. package/dist/ptable_cache_per_frame.js +66 -0
  49. package/dist/ptable_cache_per_frame.js.map +1 -0
  50. package/dist/ptable_cache_plain.cjs +54 -0
  51. package/dist/ptable_cache_plain.cjs.map +1 -0
  52. package/dist/ptable_cache_plain.d.ts +21 -0
  53. package/dist/ptable_cache_plain.d.ts.map +1 -0
  54. package/dist/ptable_cache_plain.js +51 -0
  55. package/dist/ptable_cache_plain.js.map +1 -0
  56. package/dist/ptable_def_pool.cjs +53 -0
  57. package/dist/ptable_def_pool.cjs.map +1 -0
  58. package/dist/ptable_def_pool.d.ts +21 -0
  59. package/dist/ptable_def_pool.d.ts.map +1 -0
  60. package/dist/ptable_def_pool.js +50 -0
  61. package/dist/ptable_def_pool.js.map +1 -0
  62. package/dist/ptable_pool.cjs +167 -0
  63. package/dist/ptable_pool.cjs.map +1 -0
  64. package/dist/ptable_pool.d.ts +26 -0
  65. package/dist/ptable_pool.d.ts.map +1 -0
  66. package/dist/ptable_pool.js +164 -0
  67. package/dist/ptable_pool.js.map +1 -0
  68. package/dist/ptable_shared.cjs +10 -0
  69. package/dist/ptable_shared.cjs.map +1 -0
  70. package/dist/ptable_shared.d.ts +7 -0
  71. package/dist/ptable_shared.d.ts.map +1 -0
  72. package/dist/ptable_shared.js +8 -0
  73. package/dist/ptable_shared.js.map +1 -0
  74. package/package.json +54 -0
  75. package/src/data_info_helpers.ts +26 -0
  76. package/src/driver_decl.ts +82 -0
  77. package/src/driver_double.test.ts +135 -0
  78. package/src/driver_double.ts +134 -0
  79. package/src/driver_impl.ts +535 -0
  80. package/src/index.ts +4 -0
  81. package/src/logging.ts +5 -0
  82. package/src/pframe_pool.ts +257 -0
  83. package/src/ptable_cache_per_frame.ts +86 -0
  84. package/src/ptable_cache_plain.ts +67 -0
  85. package/src/ptable_def_pool.ts +50 -0
  86. package/src/ptable_pool.ts +187 -0
  87. package/src/ptable_shared.ts +11 -0
@@ -0,0 +1,164 @@
1
+ import { bigintReplacer, PFrameDriverError, assertNever } from '@platforma-sdk/model';
2
+ import { RefCountPoolBase } from '@milaboratories/ts-helpers';
3
+ import { logPFrames } from './logging.js';
4
+ import { stableKeyFromFullPTableDef } from './ptable_shared.js';
5
+
6
+ class PTableHolder {
7
+ pFrame;
8
+ pTablePromise;
9
+ predecessor;
10
+ abortController = new AbortController();
11
+ combinedDisposeSignal;
12
+ constructor(pFrame, pFrameDisposeSignal, pTablePromise, predecessor) {
13
+ this.pFrame = pFrame;
14
+ this.pTablePromise = pTablePromise;
15
+ this.predecessor = predecessor;
16
+ this.combinedDisposeSignal = AbortSignal.any([pFrameDisposeSignal, this.abortController.signal]);
17
+ }
18
+ get disposeSignal() {
19
+ return this.combinedDisposeSignal;
20
+ }
21
+ [Symbol.dispose]() {
22
+ this.abortController.abort();
23
+ this.predecessor?.unref();
24
+ void this.pTablePromise
25
+ .then((pTable) => pTable.dispose())
26
+ .catch(() => { });
27
+ }
28
+ }
29
+ class PTablePool extends RefCountPoolBase {
30
+ pFrames;
31
+ pTableDefs;
32
+ logger;
33
+ constructor(pFrames, pTableDefs, logger) {
34
+ super();
35
+ this.pFrames = pFrames;
36
+ this.pTableDefs = pTableDefs;
37
+ this.logger = logger;
38
+ }
39
+ calculateParamsKey(params) {
40
+ return stableKeyFromFullPTableDef(params);
41
+ }
42
+ createNewResource(params, key) {
43
+ if (logPFrames()) {
44
+ this.logger('info', `PTable creation (pTableHandle = ${key}): `
45
+ + `${JSON.stringify(params, bigintReplacer)}`);
46
+ }
47
+ const handle = params.pFrameHandle;
48
+ const { pFramePromise, disposeSignal } = this.pFrames.getByKey(handle);
49
+ const defDisposeSignal = this.pTableDefs.tryGetByKey(key)?.disposeSignal;
50
+ const combinedSignal = AbortSignal.any([disposeSignal, defDisposeSignal].filter((s) => !!s));
51
+ // 3. Sort
52
+ if (params.def.sorting.length > 0) {
53
+ const predecessor = this.acquire({
54
+ ...params,
55
+ def: {
56
+ ...params.def,
57
+ sorting: [],
58
+ },
59
+ });
60
+ const { resource: { pTablePromise } } = predecessor;
61
+ const sortedTable = pTablePromise.then((pTable) => pTable.sort(params.def.sorting));
62
+ return new PTableHolder(handle, combinedSignal, sortedTable, predecessor);
63
+ }
64
+ // 2. Filter (except the case with artificial columns where cartesian creates too many rows)
65
+ if (!hasArtificialColumns(params.def.src) && params.def.filters.length > 0) {
66
+ const predecessor = this.acquire({
67
+ ...params,
68
+ def: {
69
+ ...params.def,
70
+ filters: [],
71
+ },
72
+ });
73
+ const { resource: { pTablePromise } } = predecessor;
74
+ const filteredTable = pTablePromise.then((pTable) => pTable.filter(params.def.filters));
75
+ return new PTableHolder(handle, combinedSignal, filteredTable, predecessor);
76
+ }
77
+ // 1. Join
78
+ const table = pFramePromise.then((pFrame) => pFrame.createTable({
79
+ src: joinEntryToInternal(params.def.src),
80
+ // `params.def.filters` would be non-empty only when join has artificial columns
81
+ filters: [...params.def.partitionFilters, ...params.def.filters],
82
+ }));
83
+ return new PTableHolder(handle, combinedSignal, table);
84
+ }
85
+ getByKey(key) {
86
+ const resource = super.tryGetByKey(key);
87
+ if (!resource)
88
+ throw new PFrameDriverError(`PTable not found, handle = ${key}`);
89
+ return resource;
90
+ }
91
+ }
92
+ function hasArtificialColumns(entry) {
93
+ switch (entry.type) {
94
+ case 'column':
95
+ case 'slicedColumn':
96
+ case 'inlineColumn':
97
+ return false;
98
+ case 'artificialColumn':
99
+ return true;
100
+ case 'full':
101
+ case 'inner':
102
+ return entry.entries.some(hasArtificialColumns);
103
+ case 'outer':
104
+ return hasArtificialColumns(entry.primary) || entry.secondary.some(hasArtificialColumns);
105
+ default:
106
+ assertNever(entry);
107
+ }
108
+ }
109
+ function joinEntryToInternal(entry) {
110
+ const type = entry.type;
111
+ switch (type) {
112
+ case 'column':
113
+ return {
114
+ type: 'column',
115
+ columnId: entry.column,
116
+ };
117
+ case 'slicedColumn':
118
+ return {
119
+ type: 'slicedColumn',
120
+ columnId: entry.column,
121
+ newId: entry.newId,
122
+ axisFilters: entry.axisFilters,
123
+ };
124
+ case 'artificialColumn':
125
+ return {
126
+ type: 'artificialColumn',
127
+ columnId: entry.column,
128
+ newId: entry.newId,
129
+ axesIndices: entry.axesIndices,
130
+ };
131
+ case 'inlineColumn':
132
+ return {
133
+ type: 'inlineColumn',
134
+ newId: entry.column.id,
135
+ spec: entry.column.spec,
136
+ dataInfo: {
137
+ type: 'Json',
138
+ keyLength: entry.column.spec.axesSpec.length,
139
+ data: entry.column.data.reduce((acc, row) => {
140
+ acc[JSON.stringify(row.key)] = row.val;
141
+ return acc;
142
+ }, {}),
143
+ },
144
+ };
145
+ case 'inner':
146
+ case 'full':
147
+ return {
148
+ type: entry.type,
149
+ entries: entry.entries.map((col) => joinEntryToInternal(col)),
150
+ };
151
+ case 'outer':
152
+ return {
153
+ type: 'outer',
154
+ primary: joinEntryToInternal(entry.primary),
155
+ secondary: entry.secondary.map((col) => joinEntryToInternal(col)),
156
+ };
157
+ default:
158
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
159
+ throw new PFrameDriverError(`unsupported PFrame join entry type: ${type}`);
160
+ }
161
+ }
162
+
163
+ export { PTableHolder, PTablePool };
164
+ //# sourceMappingURL=ptable_pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ptable_pool.js","sources":["../src/ptable_pool.ts"],"sourcesContent":["import {\n assertNever,\n bigintReplacer,\n PFrameDriverError,\n type PFrameHandle,\n type PTableHandle,\n type JoinEntry,\n type JsonSerializable,\n type PColumnValue,\n type PObjectId,\n} from '@platforma-sdk/model';\nimport type { PFrameInternal } from '@milaboratories/pl-model-middle-layer';\nimport { RefCountPoolBase, type PoolEntry } from '@milaboratories/ts-helpers';\nimport { logPFrames } from './logging';\nimport type { PFramePool } from './pframe_pool';\nimport { stableKeyFromFullPTableDef, type FullPTableDef } from './ptable_shared';\nimport type { PTableDefPool } from './ptable_def_pool';\n\nexport class PTableHolder implements Disposable {\n private readonly abortController = new AbortController();\n private readonly combinedDisposeSignal: AbortSignal;\n\n constructor(\n public readonly pFrame: PFrameHandle,\n pFrameDisposeSignal: AbortSignal,\n public readonly pTablePromise: Promise<PFrameInternal.PTableV7>,\n private readonly predecessor?: PoolEntry<PTableHandle, PTableHolder>,\n ) {\n this.combinedDisposeSignal = AbortSignal.any([pFrameDisposeSignal, this.abortController.signal]);\n }\n\n public get disposeSignal(): AbortSignal {\n return this.combinedDisposeSignal;\n }\n\n [Symbol.dispose](): void {\n this.abortController.abort();\n this.predecessor?.unref();\n void this.pTablePromise\n .then((pTable) => pTable.dispose())\n .catch(() => { /* mute error */ });\n }\n}\n\nexport class PTablePool<TreeEntry extends JsonSerializable>\n extends RefCountPoolBase<FullPTableDef, PTableHandle, PTableHolder> {\n constructor(\n private readonly pFrames: PFramePool<TreeEntry>,\n private readonly pTableDefs: PTableDefPool,\n private readonly logger: PFrameInternal.Logger,\n ) {\n super();\n }\n\n protected calculateParamsKey(params: FullPTableDef): PTableHandle {\n return stableKeyFromFullPTableDef(params);\n }\n\n protected createNewResource(params: FullPTableDef, key: PTableHandle): PTableHolder {\n if (logPFrames()) {\n this.logger('info',\n `PTable creation (pTableHandle = ${key}): `\n + `${JSON.stringify(params, bigintReplacer)}`,\n );\n }\n\n const handle = params.pFrameHandle;\n const { pFramePromise, disposeSignal } = this.pFrames.getByKey(handle);\n\n const defDisposeSignal = this.pTableDefs.tryGetByKey(key)?.disposeSignal;\n const combinedSignal = AbortSignal.any([disposeSignal, defDisposeSignal].filter((s) => !!s));\n\n // 3. Sort\n if (params.def.sorting.length > 0) {\n const predecessor = this.acquire({\n ...params,\n def: {\n ...params.def,\n sorting: [],\n },\n });\n const { resource: { pTablePromise } } = predecessor;\n const sortedTable = pTablePromise.then((pTable) => pTable.sort(params.def.sorting));\n return new PTableHolder(handle, combinedSignal, sortedTable, predecessor);\n }\n\n // 2. Filter (except the case with artificial columns where cartesian creates too many rows)\n if (!hasArtificialColumns(params.def.src) && params.def.filters.length > 0) {\n const predecessor = this.acquire({\n ...params,\n def: {\n ...params.def,\n filters: [],\n },\n });\n const { resource: { pTablePromise } } = predecessor;\n const filteredTable = pTablePromise.then((pTable) => pTable.filter(params.def.filters));\n return new PTableHolder(handle, combinedSignal, filteredTable, predecessor);\n }\n\n // 1. Join\n const table = pFramePromise.then((pFrame) => pFrame.createTable({\n src: joinEntryToInternal(params.def.src),\n // `params.def.filters` would be non-empty only when join has artificial columns\n filters: [...params.def.partitionFilters, ...params.def.filters],\n }));\n return new PTableHolder(handle, combinedSignal, table);\n }\n\n public getByKey(key: PTableHandle): PTableHolder {\n const resource = super.tryGetByKey(key);\n if (!resource) throw new PFrameDriverError(`PTable not found, handle = ${key}`);\n return resource;\n }\n}\n\nfunction hasArtificialColumns<T>(entry: JoinEntry<T>): boolean {\n switch (entry.type) {\n case 'column':\n case 'slicedColumn':\n case 'inlineColumn':\n return false;\n case 'artificialColumn':\n return true;\n case 'full':\n case 'inner':\n return entry.entries.some(hasArtificialColumns);\n case 'outer':\n return hasArtificialColumns(entry.primary) || entry.secondary.some(hasArtificialColumns);\n default:\n assertNever(entry);\n }\n}\n\nfunction joinEntryToInternal(entry: JoinEntry<PObjectId>): PFrameInternal.JoinEntryV4 {\n const type = entry.type;\n switch (type) {\n case 'column':\n return {\n type: 'column',\n columnId: entry.column,\n };\n case 'slicedColumn':\n return {\n type: 'slicedColumn',\n columnId: entry.column,\n newId: entry.newId,\n axisFilters: entry.axisFilters,\n };\n case 'artificialColumn':\n return {\n type: 'artificialColumn',\n columnId: entry.column,\n newId: entry.newId,\n axesIndices: entry.axesIndices,\n };\n case 'inlineColumn':\n return {\n type: 'inlineColumn',\n newId: entry.column.id,\n spec: entry.column.spec,\n dataInfo: {\n type: 'Json',\n keyLength: entry.column.spec.axesSpec.length,\n data: entry.column.data.reduce((acc, row) => {\n acc[JSON.stringify(row.key)] = row.val;\n return acc;\n }, {} as Record<string, PColumnValue>),\n },\n };\n case 'inner':\n case 'full':\n return {\n type: entry.type,\n entries: entry.entries.map((col) => joinEntryToInternal(col)),\n };\n case 'outer':\n return {\n type: 'outer',\n primary: joinEntryToInternal(entry.primary),\n secondary: entry.secondary.map((col) => joinEntryToInternal(col)),\n };\n default:\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n throw new PFrameDriverError(`unsupported PFrame join entry type: ${type satisfies never}`);\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ 'use strict';
2
+
3
+ var tsHelpers = require('@milaboratories/ts-helpers');
4
+
5
+ function stableKeyFromFullPTableDef(data) {
6
+ return tsHelpers.hashJson(data);
7
+ }
8
+
9
+ exports.stableKeyFromFullPTableDef = stableKeyFromFullPTableDef;
10
+ //# sourceMappingURL=ptable_shared.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ptable_shared.cjs","sources":["../src/ptable_shared.ts"],"sourcesContent":["import type { PObjectId, PFrameHandle, PTableDef, PTableHandle } from '@platforma-sdk/model';\nimport { hashJson } from '@milaboratories/ts-helpers';\n\nexport type FullPTableDef = {\n pFrameHandle: PFrameHandle;\n def: PTableDef<PObjectId>;\n};\n\nexport function stableKeyFromFullPTableDef(data: FullPTableDef): PTableHandle {\n return hashJson(data) as string as PTableHandle;\n}\n"],"names":["hashJson"],"mappings":";;;;AAQM,SAAU,0BAA0B,CAAC,IAAmB,EAAA;AAC5D,IAAA,OAAOA,kBAAQ,CAAC,IAAI,CAA2B;AACjD;;;;"}
@@ -0,0 +1,7 @@
1
+ import type { PObjectId, PFrameHandle, PTableDef, PTableHandle } from '@platforma-sdk/model';
2
+ export type FullPTableDef = {
3
+ pFrameHandle: PFrameHandle;
4
+ def: PTableDef<PObjectId>;
5
+ };
6
+ export declare function stableKeyFromFullPTableDef(data: FullPTableDef): PTableHandle;
7
+ //# sourceMappingURL=ptable_shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ptable_shared.d.ts","sourceRoot":"","sources":["../src/ptable_shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAG7F,MAAM,MAAM,aAAa,GAAG;IAC1B,YAAY,EAAE,YAAY,CAAC;IAC3B,GAAG,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC3B,CAAC;AAEF,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,aAAa,GAAG,YAAY,CAE5E"}
@@ -0,0 +1,8 @@
1
+ import { hashJson } from '@milaboratories/ts-helpers';
2
+
3
+ function stableKeyFromFullPTableDef(data) {
4
+ return hashJson(data);
5
+ }
6
+
7
+ export { stableKeyFromFullPTableDef };
8
+ //# sourceMappingURL=ptable_shared.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ptable_shared.js","sources":["../src/ptable_shared.ts"],"sourcesContent":["import type { PObjectId, PFrameHandle, PTableDef, PTableHandle } from '@platforma-sdk/model';\nimport { hashJson } from '@milaboratories/ts-helpers';\n\nexport type FullPTableDef = {\n pFrameHandle: PFrameHandle;\n def: PTableDef<PObjectId>;\n};\n\nexport function stableKeyFromFullPTableDef(data: FullPTableDef): PTableHandle {\n return hashJson(data) as string as PTableHandle;\n}\n"],"names":[],"mappings":";;AAQM,SAAU,0BAA0B,CAAC,IAAmB,EAAA;AAC5D,IAAA,OAAO,QAAQ,CAAC,IAAI,CAA2B;AACjD;;;;"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@milaboratories/pf-driver",
3
+ "version": "1.0.0",
4
+ "description": "PFrameDriver implementation abstracted from Middle Layer",
5
+ "engines": {
6
+ "node": ">=22.19.0"
7
+ },
8
+ "type": "module",
9
+ "types": "./dist/index.d.ts",
10
+ "main": "./dist/index.js",
11
+ "module": "./dist/index.js",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs"
17
+ }
18
+ },
19
+ "files": [
20
+ "./dist/**/*",
21
+ "./src/**/*"
22
+ ],
23
+ "keywords": [],
24
+ "license": "UNLICENSED",
25
+ "devDependencies": {
26
+ "eslint": "^9.25.1",
27
+ "tsconfig-paths": "^4.2.0",
28
+ "typescript": "~5.6.3",
29
+ "tslib": "~2.7.0",
30
+ "vitest": "^4.0.7",
31
+ "@vitest/coverage-v8": "^4.0.7",
32
+ "@types/node": "~24.5.2",
33
+ "@milaboratories/eslint-config": "1.0.4",
34
+ "@milaboratories/build-configs": "1.0.8",
35
+ "@milaboratories/ts-builder": "1.0.5",
36
+ "@milaboratories/ts-configs": "1.0.6"
37
+ },
38
+ "dependencies": {
39
+ "@milaboratories/pframes-rs-node": "1.0.103",
40
+ "lru-cache": "^11.2.2",
41
+ "es-toolkit": "^1.39.10",
42
+ "@milaboratories/ts-helpers": "1.5.2",
43
+ "@platforma-sdk/model": "1.45.26",
44
+ "@milaboratories/pl-model-middle-layer": "1.8.36"
45
+ },
46
+ "scripts": {
47
+ "type-check": "ts-builder types --target node",
48
+ "build": "ts-builder build --target node",
49
+ "watch": "ts-builder build --target node --watch",
50
+ "lint": "eslint .",
51
+ "test": "vitest run --coverage",
52
+ "do-pack": "rm -f *.tgz && pnpm pack && mv *.tgz package.tgz"
53
+ }
54
+ }
@@ -0,0 +1,26 @@
1
+ import {
2
+ PFrameDriverError,
3
+ type PColumnSpec,
4
+ type PColumnValues,
5
+ type JsonDataInfo,
6
+ type PColumnValue,
7
+ } from '@platforma-sdk/model';
8
+
9
+ export function makeJsonDataInfo(
10
+ spec: PColumnSpec,
11
+ data: PColumnValues,
12
+ ): JsonDataInfo {
13
+ const keyLength = spec.axesSpec.length;
14
+ const jsonData: Record<string, PColumnValue> = {};
15
+ for (const { key, val } of data) {
16
+ if (key.length !== keyLength)
17
+ throw new PFrameDriverError(`inline column key length ${key.length} differs from axes count ${keyLength}`);
18
+ jsonData[JSON.stringify(key)] = val;
19
+ }
20
+
21
+ return {
22
+ type: 'Json',
23
+ keyLength,
24
+ data: jsonData,
25
+ };
26
+ }
@@ -0,0 +1,82 @@
1
+ import type {
2
+ CalculateTableDataRequest,
3
+ CalculateTableDataResponse,
4
+ PColumn,
5
+ PFrameDef,
6
+ PFrameDriver,
7
+ PFrameHandle,
8
+ PObjectId,
9
+ PTableDef,
10
+ PTableHandle,
11
+ PTableShape,
12
+ PTableVector,
13
+ TableRange,
14
+ UniqueValuesRequest,
15
+ UniqueValuesResponse,
16
+ } from '@platforma-sdk/model';
17
+ import type { PoolEntry } from '@milaboratories/ts-helpers';
18
+
19
+ /**
20
+ * Extends public and safe SDK's driver API with methods used internally in the middle
21
+ * layer and in tests.
22
+ */
23
+ export interface AbstractInternalPFrameDriver<PColumnData>
24
+ extends PFrameDriver, AsyncDisposable {
25
+ /** Dispose the driver and all its resources. */
26
+ dispose(): Promise<void>;
27
+
28
+ /**
29
+ * Dump active PFrames allocations in pprof format.
30
+ * The result of this function should be saved as `profile.pb.gz`.
31
+ * Use {@link https://pprof.me/} or {@link https://www.speedscope.app/}
32
+ * to view the allocation flamechart.
33
+ * @warning This method will always reject on Windows!
34
+ */
35
+ pprofDump(): Promise<Uint8Array>;
36
+
37
+ /** Create a new PFrame */
38
+ createPFrame(
39
+ def: PFrameDef<PColumn<PColumnData>>,
40
+ ): PoolEntry<PFrameHandle>;
41
+
42
+ /** Create a new PTable */
43
+ createPTable(
44
+ def: PTableDef<PColumn<PColumnData>>,
45
+ ): PoolEntry<PTableHandle>;
46
+
47
+ /** Calculates data for the table and returns complete data representation of it */
48
+ calculateTableData(
49
+ handle: PFrameHandle,
50
+ request: CalculateTableDataRequest<PObjectId>,
51
+ range: TableRange | undefined,
52
+ signal?: AbortSignal
53
+ ): Promise<CalculateTableDataResponse>;
54
+
55
+ /** Calculate set of unique values for a specific axis for the filtered set of records */
56
+ getUniqueValues(
57
+ handle: PFrameHandle,
58
+ request: UniqueValuesRequest,
59
+ signal?: AbortSignal
60
+ ): Promise<UniqueValuesResponse>;
61
+
62
+ /** Unified table shape */
63
+ getShape(
64
+ handle: PTableHandle,
65
+ signal?: AbortSignal,
66
+ ): Promise<PTableShape>;
67
+
68
+ /**
69
+ * Retrieve the data from the table. To retrieve only data required, it can be
70
+ * sliced both horizontally ({@link columnIndices}) and vertically
71
+ * ({@link range}).
72
+ *
73
+ * @param columnIndices unified indices of columns to be retrieved
74
+ * @param range optionally limit the range of records to retrieve
75
+ * */
76
+ getData(
77
+ handle: PTableHandle,
78
+ columnIndices: number[],
79
+ range: TableRange | undefined,
80
+ signal?: AbortSignal,
81
+ ): Promise<PTableVector[]>;
82
+ }
@@ -0,0 +1,135 @@
1
+ import {
2
+ pTableValue,
3
+ type CalculateTableDataResponse,
4
+ type PFrameDriver,
5
+ type PObjectId,
6
+ } from '@platforma-sdk/model';
7
+ import { test } from 'vitest';
8
+ import { join } from 'node:path';
9
+ import {
10
+ createPFrameDriverDouble,
11
+ makeFolderPath,
12
+ } from './driver_double';
13
+ import { readJsonSync } from '@milaboratories/ts-helpers';
14
+
15
+ test('inline column support', async ({ expect }) => {
16
+ // Model context
17
+
18
+ await using driver = await createPFrameDriverDouble({});
19
+ using pFrame = driver.createPFrame([{
20
+ id: 'column1' as PObjectId,
21
+ spec: {
22
+ kind: 'PColumn',
23
+ axesSpec: [{
24
+ name: 'axis1',
25
+ type: 'String',
26
+ }],
27
+ name: 'column1',
28
+ valueType: 'Int',
29
+ },
30
+ data: [
31
+ {
32
+ key: ['axis1'],
33
+ val: 1,
34
+ },
35
+ ],
36
+ }]);
37
+
38
+ // UI context
39
+
40
+ const uiDriver: PFrameDriver = driver;
41
+ const pFrameHandle = pFrame.key;
42
+
43
+ const data = await uiDriver.calculateTableData(pFrameHandle, {
44
+ src: {
45
+ type: 'column',
46
+ column: 'column1' as PObjectId,
47
+ },
48
+ filters: [],
49
+ sorting: [],
50
+ });
51
+
52
+ expect(data).toEqual([
53
+ {
54
+ spec: {
55
+ type: 'axis',
56
+ id: {
57
+ name: 'axis1',
58
+ type: 'String',
59
+ },
60
+ spec: {
61
+ name: 'axis1',
62
+ type: 'String',
63
+ },
64
+ },
65
+ data: {
66
+ type: 'String',
67
+ data: ['axis1'],
68
+ isNA: new Uint8Array(),
69
+ absent: new Uint8Array(),
70
+ },
71
+ },
72
+ {
73
+ spec: {
74
+ type: 'column',
75
+ id: 'column1' as PObjectId,
76
+ spec: {
77
+ kind: 'PColumn',
78
+ axesSpec: [{
79
+ name: 'axis1',
80
+ type: 'String',
81
+ }],
82
+ name: 'column1',
83
+ valueType: 'Int',
84
+ },
85
+ },
86
+ data: {
87
+ type: 'Int',
88
+ data: new Int32Array([1]),
89
+ isNA: new Uint8Array(),
90
+ absent: new Uint8Array(),
91
+ },
92
+ },
93
+ ] satisfies CalculateTableDataResponse);
94
+ })
95
+
96
+ test.for([
97
+ { testCase: '01_json' },
98
+ { testCase: '02_binary' },
99
+ { testCase: '03_parquet' },
100
+ ])(`stored column support - $testCase`, async ({ testCase }, { expect }) => {
101
+ const dataFolder = makeFolderPath(join(__dirname, '..', 'assets', testCase));
102
+
103
+ // Model context
104
+
105
+ await using driver = await createPFrameDriverDouble({ dataFolder });
106
+ const pFrame = driver.createPFrame([{
107
+ id: 'column' as PObjectId,
108
+ spec: readJsonSync(join(dataFolder, 'column.spec')),
109
+ data: readJsonSync(join(dataFolder, 'column.datainfo')),
110
+ }]);
111
+
112
+ // UI context
113
+
114
+ const uiDriver: PFrameDriver = driver;
115
+ const pFrameHandle = pFrame.key;
116
+
117
+ const data = await uiDriver.calculateTableData(pFrameHandle, {
118
+ src: {
119
+ type: 'column',
120
+ column: 'column' as PObjectId,
121
+ },
122
+ filters: [],
123
+ sorting: [],
124
+ });
125
+ const result = {
126
+ spec: data.map((d) => d.spec),
127
+ data: data.map((d) => d.data)
128
+ .map((d) => [...d.data.keys()].map((i) => pTableValue(d, i, {
129
+ absent: "|~|",
130
+ na: null,
131
+ }))),
132
+ }
133
+ const expected = readJsonSync(join(dataFolder, 'response.json'));
134
+ expect(result).toEqual(expected);
135
+ })
@@ -0,0 +1,134 @@
1
+ import {
2
+ isDataInfo,
3
+ PFrameDriverError,
4
+ type Branded,
5
+ type PColumnSpec,
6
+ type PColumnValues,
7
+ } from '@platforma-sdk/model';
8
+ import { PFrameInternal } from '@milaboratories/pl-model-middle-layer';
9
+ import { RefCountPoolBase, type PoolEntry } from '@milaboratories/ts-helpers';
10
+ import { HttpHelpers } from '@milaboratories/pframes-rs-node';
11
+ import fs from 'node:fs';
12
+ import path from 'node:path';
13
+ import { tmpdir } from 'node:os';
14
+ import type { AbstractInternalPFrameDriver } from './driver_decl';
15
+ import {
16
+ AbstractPFrameDriver,
17
+ type LocalBlobProvider,
18
+ type RemoteBlobProvider,
19
+ } from './driver_impl';
20
+ import { makeJsonDataInfo } from './data_info_helpers';
21
+
22
+ export type FileName = Branded<string, 'FileName'>;
23
+ export type FilePath = Branded<string, 'FilePath'>;
24
+ export type FolderPath = Branded<string, 'FolderPath'>;
25
+
26
+ export function makeFolderPath(dataFolder: string): FolderPath {
27
+ if (!fs.statSync(dataFolder, { throwIfNoEntry: false })?.isDirectory()) {
28
+ throw new PFrameDriverError(`Data folder ${dataFolder} does not exist`);
29
+ }
30
+ return dataFolder as FolderPath;
31
+ }
32
+
33
+ function makeBlobId(res: FileName): PFrameInternal.PFrameBlobId {
34
+ return res as string;
35
+ }
36
+
37
+ class LocalBlobProviderImpl
38
+ extends RefCountPoolBase<FileName, PFrameInternal.PFrameBlobId, FilePath>
39
+ implements LocalBlobProvider<FileName> {
40
+ constructor(private readonly dataFolder: FolderPath) {
41
+ super();
42
+ }
43
+
44
+ protected calculateParamsKey(params: FileName): PFrameInternal.PFrameBlobId {
45
+ return makeBlobId(params);
46
+ }
47
+
48
+ protected createNewResource(params: FileName, _key: PFrameInternal.PFrameBlobId): FilePath {
49
+ const filePath = path.join(this.dataFolder, params);
50
+ if (!fs.statSync(filePath, { throwIfNoEntry: false })?.isFile()) {
51
+ throw new PFrameDriverError(`File ${filePath} does not exist`);
52
+ }
53
+ return filePath as FilePath;
54
+ }
55
+
56
+ public getByKey(blobId: PFrameInternal.PFrameBlobId): FilePath {
57
+ const resource = super.tryGetByKey(blobId);
58
+ if (!resource) throw new PFrameDriverError(`Local blob with id ${blobId} not found.`);
59
+ return resource;
60
+ }
61
+
62
+ public makeDataSource(signal: AbortSignal): Omit<PFrameInternal.PFrameDataSourceV2, 'parquetServer'> {
63
+ return {
64
+ preloadBlob: async (_blobIds: PFrameInternal.PFrameBlobId[]) => {},
65
+ resolveBlobContent: async (blobId: PFrameInternal.PFrameBlobId) => {
66
+ const filePath = this.getByKey(blobId);
67
+ return await fs.promises.readFile(filePath, { signal });
68
+ },
69
+ };
70
+ }
71
+ }
72
+
73
+ class RemoteBlobProviderImpl implements RemoteBlobProvider<FileName> {
74
+ constructor(
75
+ private readonly pool: LocalBlobProviderImpl,
76
+ private readonly server: PFrameInternal.HttpServer,
77
+ ) {}
78
+
79
+ public static async init(
80
+ dataFolder: FolderPath,
81
+ logger: PFrameInternal.Logger,
82
+ serverOptions: Omit<PFrameInternal.HttpServerOptions, 'handler'>,
83
+ ): Promise<RemoteBlobProviderImpl> {
84
+ const pool = new LocalBlobProviderImpl(dataFolder);
85
+
86
+ const underlyingStore = await HttpHelpers.createFsStore({ rootDir: dataFolder, logger });
87
+ const store: PFrameInternal.ObjectStore = {
88
+ request: (filename, params) => {
89
+ const blobId = filename.slice(0, -PFrameInternal.ParquetExtension.length);
90
+ return underlyingStore.request(blobId as PFrameInternal.ParquetFileName, params);
91
+ },
92
+ };
93
+
94
+ const handler = HttpHelpers.createRequestHandler({ store });
95
+ const server = await HttpHelpers.createHttpServer({ ...serverOptions, handler });
96
+
97
+ return new RemoteBlobProviderImpl(pool, server);
98
+ }
99
+
100
+ public acquire(params: FileName): PoolEntry {
101
+ return this.pool.acquire(params);
102
+ }
103
+
104
+ public httpServerInfo(): PFrameInternal.HttpServerInfo {
105
+ return this.server.info;
106
+ }
107
+
108
+ async [Symbol.asyncDispose](): Promise<void> {
109
+ await this.server.stop();
110
+ }
111
+ }
112
+
113
+ export async function createPFrameDriverDouble({
114
+ dataFolder = tmpdir() as FolderPath,
115
+ logger = () => {},
116
+ }: {
117
+ dataFolder?: FolderPath;
118
+ logger?: PFrameInternal.Logger;
119
+ }): Promise<AbstractInternalPFrameDriver<PFrameInternal.DataInfo<FileName> | PColumnValues>> {
120
+ const localBlobProvider = new LocalBlobProviderImpl(dataFolder);
121
+ const remoteBlobProvider = await RemoteBlobProviderImpl.init(dataFolder, logger, {});
122
+
123
+ const resolveDataInfo = (
124
+ spec: PColumnSpec,
125
+ data: PFrameInternal.DataInfo<FileName> | PColumnValues,
126
+ ) => isDataInfo(data) ? data : makeJsonDataInfo(spec, data);
127
+
128
+ return new AbstractPFrameDriver({
129
+ logger,
130
+ localBlobProvider,
131
+ remoteBlobProvider,
132
+ resolveDataInfo,
133
+ });
134
+ }