jsonstat-io 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.
Files changed (99) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +200 -0
  3. package/dist/arrow/index.cjs +60 -0
  4. package/dist/arrow/index.cjs.map +1 -0
  5. package/dist/arrow/index.d.cts +125 -0
  6. package/dist/arrow/index.d.ts +125 -0
  7. package/dist/arrow/index.js +3 -0
  8. package/dist/arrow/index.js.map +1 -0
  9. package/dist/arrowToCube-BdRWZ5oG.d.cts +29 -0
  10. package/dist/arrowToCube-Mjr79ZHM.d.ts +29 -0
  11. package/dist/chunk-2HY7NRKX.js +259 -0
  12. package/dist/chunk-2HY7NRKX.js.map +1 -0
  13. package/dist/chunk-62NIY7ML.js +191 -0
  14. package/dist/chunk-62NIY7ML.js.map +1 -0
  15. package/dist/chunk-AXUZF6O5.cjs +352 -0
  16. package/dist/chunk-AXUZF6O5.cjs.map +1 -0
  17. package/dist/chunk-EFRDFQOT.js +335 -0
  18. package/dist/chunk-EFRDFQOT.js.map +1 -0
  19. package/dist/chunk-GDKDYLZ4.cjs +263 -0
  20. package/dist/chunk-GDKDYLZ4.cjs.map +1 -0
  21. package/dist/chunk-IDTQZG4B.js +432 -0
  22. package/dist/chunk-IDTQZG4B.js.map +1 -0
  23. package/dist/chunk-KFIKGBIJ.cjs +200 -0
  24. package/dist/chunk-KFIKGBIJ.cjs.map +1 -0
  25. package/dist/chunk-L65CRXTV.js +64 -0
  26. package/dist/chunk-L65CRXTV.js.map +1 -0
  27. package/dist/chunk-PHLCWTHB.cjs +446 -0
  28. package/dist/chunk-PHLCWTHB.cjs.map +1 -0
  29. package/dist/chunk-VQCS4LVD.cjs +166 -0
  30. package/dist/chunk-VQCS4LVD.cjs.map +1 -0
  31. package/dist/chunk-VYS7DPB3.js +162 -0
  32. package/dist/chunk-VYS7DPB3.js.map +1 -0
  33. package/dist/chunk-ZEDTWRDN.cjs +70 -0
  34. package/dist/chunk-ZEDTWRDN.cjs.map +1 -0
  35. package/dist/cli/index.cjs +337 -0
  36. package/dist/cli/index.cjs.map +1 -0
  37. package/dist/cli/index.d.cts +90 -0
  38. package/dist/cli/index.d.ts +90 -0
  39. package/dist/cli/index.js +333 -0
  40. package/dist/cli/index.js.map +1 -0
  41. package/dist/cubeBuilder-BEGA4C5Y.js +4 -0
  42. package/dist/cubeBuilder-BEGA4C5Y.js.map +1 -0
  43. package/dist/cubeBuilder-ZU76VVEX.cjs +25 -0
  44. package/dist/cubeBuilder-ZU76VVEX.cjs.map +1 -0
  45. package/dist/cubeReader-7QVUF3TI.js +4 -0
  46. package/dist/cubeReader-7QVUF3TI.js.map +1 -0
  47. package/dist/cubeReader-UN2BHQWK.cjs +21 -0
  48. package/dist/cubeReader-UN2BHQWK.cjs.map +1 -0
  49. package/dist/index.cjs +172 -0
  50. package/dist/index.cjs.map +1 -0
  51. package/dist/index.d.cts +445 -0
  52. package/dist/index.d.ts +445 -0
  53. package/dist/index.js +7 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/ir-BArfNxo-.d.cts +143 -0
  56. package/dist/ir-Jae2ymov.d.ts +143 -0
  57. package/dist/jsonstat-BX4mBLci.d.cts +179 -0
  58. package/dist/jsonstat-BX4mBLci.d.ts +179 -0
  59. package/dist/sources/csv.cjs +40 -0
  60. package/dist/sources/csv.cjs.map +1 -0
  61. package/dist/sources/csv.d.cts +112 -0
  62. package/dist/sources/csv.d.ts +112 -0
  63. package/dist/sources/csv.js +3 -0
  64. package/dist/sources/csv.js.map +1 -0
  65. package/dist/sources/csvw.cjs +236 -0
  66. package/dist/sources/csvw.cjs.map +1 -0
  67. package/dist/sources/csvw.d.cts +143 -0
  68. package/dist/sources/csvw.d.ts +143 -0
  69. package/dist/sources/csvw.js +230 -0
  70. package/dist/sources/csvw.js.map +1 -0
  71. package/dist/sources/duckdb.cjs +121 -0
  72. package/dist/sources/duckdb.cjs.map +1 -0
  73. package/dist/sources/duckdb.d.cts +111 -0
  74. package/dist/sources/duckdb.d.ts +111 -0
  75. package/dist/sources/duckdb.js +115 -0
  76. package/dist/sources/duckdb.js.map +1 -0
  77. package/dist/sources/parquet.cjs +117 -0
  78. package/dist/sources/parquet.cjs.map +1 -0
  79. package/dist/sources/parquet.d.cts +83 -0
  80. package/dist/sources/parquet.d.ts +83 -0
  81. package/dist/sources/parquet.js +111 -0
  82. package/dist/sources/parquet.js.map +1 -0
  83. package/dist/sources/polars.cjs +94 -0
  84. package/dist/sources/polars.cjs.map +1 -0
  85. package/dist/sources/polars.d.cts +91 -0
  86. package/dist/sources/polars.d.ts +91 -0
  87. package/dist/sources/polars.js +87 -0
  88. package/dist/sources/polars.js.map +1 -0
  89. package/docs/api.md +322 -0
  90. package/docs/architecture.md +140 -0
  91. package/docs/cli.md +159 -0
  92. package/docs/formats/arrow.md +111 -0
  93. package/docs/formats/csv.md +115 -0
  94. package/docs/formats/csvw.md +152 -0
  95. package/docs/formats/duckdb.md +151 -0
  96. package/docs/formats/parquet.md +132 -0
  97. package/docs/formats/polars.md +111 -0
  98. package/docs/mapping.md +136 -0
  99. package/package.json +119 -0
@@ -0,0 +1,111 @@
1
+ import { O as Observations } from '../ir-BArfNxo-.cjs';
2
+ import { J as JsonStatDataset } from '../jsonstat-BX4mBLci.cjs';
3
+ import { A as ArrowToCubeOptions } from '../arrowToCube-BdRWZ5oG.cjs';
4
+ import 'apache-arrow';
5
+
6
+ /**
7
+ * DuckDB adapter — `jsonstat-io/duckdb`.
8
+ *
9
+ * **Import:** runs a SQL query against DuckDB and funnels the result (as an
10
+ * Arrow [`Table`]) through the Arrow hub
11
+ * ([`arrowToCube`](../arrow/arrowToCube.ts)).
12
+ *
13
+ * **Export:** [`cubeToDuckdb`] registers an Arrow [`Table`] built from the
14
+ * [`Observations`] IR into a DuckDB connection as a named table.
15
+ *
16
+ * Two optional peer backends are supported, picked automatically:
17
+ *
18
+ * - **Browser**: `@duckdb/duckdb-wasm` — instantiate via `@duckdb/duckdb-wasm`
19
+ * and pass the connection (or a factory) to [`duckdbToCube`].
20
+ * - **Node**: `duckdb-async` — a native binding; pass the connection.
21
+ *
22
+ * Both expose an `.arrowResult()` / `.arrow()` style API that yields an Arrow
23
+ * Table. The adapter normalizes the two shapes.
24
+ *
25
+ * `@duckdb/duckdb-wasm` and `duckdb-async` are **optional peer dependencies**.
26
+ */
27
+
28
+ declare class DuckdbSourceError extends Error {
29
+ constructor(message: string);
30
+ }
31
+ /**
32
+ * A minimal connection interface covering both duckdb-wasm and duckdb-async.
33
+ * The adapter only requires a way to run a query and obtain an Arrow Table.
34
+ */
35
+ interface DuckdbConnection {
36
+ /** Run a SQL query and return an Apache Arrow Table. */
37
+ arrow(query: string): Promise<any>;
38
+ /**
39
+ * Register an Arrow Table under a view name (duckdb-async style). Optional:
40
+ * the export path falls back to `insert_arrow_table` / `conn.register` if
41
+ * this is absent.
42
+ */
43
+ register?(viewName: string, table: any): Promise<void>;
44
+ /** DuckDB-wasm style: insert an Arrow Table into a named table. */
45
+ insert_arrow_table?(table: any, options?: {
46
+ name?: string;
47
+ }): Promise<void>;
48
+ /** Run an arbitrary SQL statement (no Arrow result). */
49
+ run?(query: string): Promise<unknown>;
50
+ close?(): Promise<void>;
51
+ }
52
+ interface DuckdbToCubeOptions extends ArrowToCubeOptions {
53
+ /**
54
+ * A factory that returns a fresh connection. Useful for browser setups where
55
+ * the wasm module must be instantiated lazily. If provided, takes precedence
56
+ * over `connection` and is closed after use.
57
+ */
58
+ connect?: () => Promise<DuckdbConnection>;
59
+ }
60
+ /**
61
+ * Run a SQL query against DuckDB and convert the result to the
62
+ * [`Observations`] IR via the Arrow hub.
63
+ *
64
+ * @param connectionOrFactory A [`DuckdbConnection`] or (via `options.connect`)
65
+ * a factory creating one.
66
+ * @param query SQL to execute.
67
+ * @throws [`DuckdbSourceError`] on query or conversion failure.
68
+ */
69
+ declare function duckdbToCube(connection: DuckdbConnection, query: string, options?: DuckdbToCubeOptions): Promise<Observations>;
70
+ /** Convenience: DuckDB query → JSON-stat [`Dataset`]. */
71
+ declare function duckdbToDataset(connection: DuckdbConnection, query: string, options?: DuckdbToCubeOptions): Promise<JsonStatDataset>;
72
+ /**
73
+ * Helper for Node users of `duckdb-async`: create a connection from a
74
+ * Database instance. Importing `duckdb-async` is lazy so browser bundles stay
75
+ * lean.
76
+ */
77
+ declare function openDuckdbNode(path?: string): Promise<DuckdbConnection>;
78
+ interface CubeToDuckdbOptions {
79
+ /** Name of the target table/view to create. Defaults to `"observations"`. */
80
+ tableName?: string;
81
+ /**
82
+ * `"view"` (default): registers the Arrow Table as a queryable view via
83
+ * `conn.register` (cheap; the table is not copied). `"table"`: creates and
84
+ * populates a physical table via DuckDB's `insert_arrow_table` / `CREATE
85
+ * TABLE AS`.
86
+ */
87
+ mode?: "view" | "table";
88
+ }
89
+ /**
90
+ * Write the [`Observations`](../model/ir.ts) IR into a DuckDB connection as a
91
+ * named table (or view).
92
+ *
93
+ * The IR is first converted to an Arrow [`Table`] via [`cubeToArrow`], then
94
+ * registered into the connection. All `jsonstat.*` schema/field metadata is
95
+ * preserved on the Arrow schema, so a subsequent `SELECT * FROM <table>` →
96
+ * [`arrowToCube`] round-trips the model.
97
+ *
98
+ * @returns The name of the created table/view.
99
+ * @throws [`DuckdbSourceError`] if the connection cannot ingest Arrow tables.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * import { openDuckdbNode, cubeToDuckdb } from "jsonstat-io/duckdb";
104
+ * const conn = await openDuckdbNode();
105
+ * const name = await cubeToDuckdb(conn, observations, { tableName: "sales" });
106
+ * const rows = await conn.arrow(`SELECT * FROM ${name} LIMIT 5`);
107
+ * ```
108
+ */
109
+ declare function cubeToDuckdb(conn: DuckdbConnection, obs: Observations, options?: CubeToDuckdbOptions): Promise<string>;
110
+
111
+ export { type CubeToDuckdbOptions, type DuckdbConnection, DuckdbSourceError, type DuckdbToCubeOptions, cubeToDuckdb, duckdbToCube, duckdbToDataset, openDuckdbNode };
@@ -0,0 +1,111 @@
1
+ import { O as Observations } from '../ir-Jae2ymov.js';
2
+ import { J as JsonStatDataset } from '../jsonstat-BX4mBLci.js';
3
+ import { A as ArrowToCubeOptions } from '../arrowToCube-Mjr79ZHM.js';
4
+ import 'apache-arrow';
5
+
6
+ /**
7
+ * DuckDB adapter — `jsonstat-io/duckdb`.
8
+ *
9
+ * **Import:** runs a SQL query against DuckDB and funnels the result (as an
10
+ * Arrow [`Table`]) through the Arrow hub
11
+ * ([`arrowToCube`](../arrow/arrowToCube.ts)).
12
+ *
13
+ * **Export:** [`cubeToDuckdb`] registers an Arrow [`Table`] built from the
14
+ * [`Observations`] IR into a DuckDB connection as a named table.
15
+ *
16
+ * Two optional peer backends are supported, picked automatically:
17
+ *
18
+ * - **Browser**: `@duckdb/duckdb-wasm` — instantiate via `@duckdb/duckdb-wasm`
19
+ * and pass the connection (or a factory) to [`duckdbToCube`].
20
+ * - **Node**: `duckdb-async` — a native binding; pass the connection.
21
+ *
22
+ * Both expose an `.arrowResult()` / `.arrow()` style API that yields an Arrow
23
+ * Table. The adapter normalizes the two shapes.
24
+ *
25
+ * `@duckdb/duckdb-wasm` and `duckdb-async` are **optional peer dependencies**.
26
+ */
27
+
28
+ declare class DuckdbSourceError extends Error {
29
+ constructor(message: string);
30
+ }
31
+ /**
32
+ * A minimal connection interface covering both duckdb-wasm and duckdb-async.
33
+ * The adapter only requires a way to run a query and obtain an Arrow Table.
34
+ */
35
+ interface DuckdbConnection {
36
+ /** Run a SQL query and return an Apache Arrow Table. */
37
+ arrow(query: string): Promise<any>;
38
+ /**
39
+ * Register an Arrow Table under a view name (duckdb-async style). Optional:
40
+ * the export path falls back to `insert_arrow_table` / `conn.register` if
41
+ * this is absent.
42
+ */
43
+ register?(viewName: string, table: any): Promise<void>;
44
+ /** DuckDB-wasm style: insert an Arrow Table into a named table. */
45
+ insert_arrow_table?(table: any, options?: {
46
+ name?: string;
47
+ }): Promise<void>;
48
+ /** Run an arbitrary SQL statement (no Arrow result). */
49
+ run?(query: string): Promise<unknown>;
50
+ close?(): Promise<void>;
51
+ }
52
+ interface DuckdbToCubeOptions extends ArrowToCubeOptions {
53
+ /**
54
+ * A factory that returns a fresh connection. Useful for browser setups where
55
+ * the wasm module must be instantiated lazily. If provided, takes precedence
56
+ * over `connection` and is closed after use.
57
+ */
58
+ connect?: () => Promise<DuckdbConnection>;
59
+ }
60
+ /**
61
+ * Run a SQL query against DuckDB and convert the result to the
62
+ * [`Observations`] IR via the Arrow hub.
63
+ *
64
+ * @param connectionOrFactory A [`DuckdbConnection`] or (via `options.connect`)
65
+ * a factory creating one.
66
+ * @param query SQL to execute.
67
+ * @throws [`DuckdbSourceError`] on query or conversion failure.
68
+ */
69
+ declare function duckdbToCube(connection: DuckdbConnection, query: string, options?: DuckdbToCubeOptions): Promise<Observations>;
70
+ /** Convenience: DuckDB query → JSON-stat [`Dataset`]. */
71
+ declare function duckdbToDataset(connection: DuckdbConnection, query: string, options?: DuckdbToCubeOptions): Promise<JsonStatDataset>;
72
+ /**
73
+ * Helper for Node users of `duckdb-async`: create a connection from a
74
+ * Database instance. Importing `duckdb-async` is lazy so browser bundles stay
75
+ * lean.
76
+ */
77
+ declare function openDuckdbNode(path?: string): Promise<DuckdbConnection>;
78
+ interface CubeToDuckdbOptions {
79
+ /** Name of the target table/view to create. Defaults to `"observations"`. */
80
+ tableName?: string;
81
+ /**
82
+ * `"view"` (default): registers the Arrow Table as a queryable view via
83
+ * `conn.register` (cheap; the table is not copied). `"table"`: creates and
84
+ * populates a physical table via DuckDB's `insert_arrow_table` / `CREATE
85
+ * TABLE AS`.
86
+ */
87
+ mode?: "view" | "table";
88
+ }
89
+ /**
90
+ * Write the [`Observations`](../model/ir.ts) IR into a DuckDB connection as a
91
+ * named table (or view).
92
+ *
93
+ * The IR is first converted to an Arrow [`Table`] via [`cubeToArrow`], then
94
+ * registered into the connection. All `jsonstat.*` schema/field metadata is
95
+ * preserved on the Arrow schema, so a subsequent `SELECT * FROM <table>` →
96
+ * [`arrowToCube`] round-trips the model.
97
+ *
98
+ * @returns The name of the created table/view.
99
+ * @throws [`DuckdbSourceError`] if the connection cannot ingest Arrow tables.
100
+ *
101
+ * @example
102
+ * ```ts
103
+ * import { openDuckdbNode, cubeToDuckdb } from "jsonstat-io/duckdb";
104
+ * const conn = await openDuckdbNode();
105
+ * const name = await cubeToDuckdb(conn, observations, { tableName: "sales" });
106
+ * const rows = await conn.arrow(`SELECT * FROM ${name} LIMIT 5`);
107
+ * ```
108
+ */
109
+ declare function cubeToDuckdb(conn: DuckdbConnection, obs: Observations, options?: CubeToDuckdbOptions): Promise<string>;
110
+
111
+ export { type CubeToDuckdbOptions, type DuckdbConnection, DuckdbSourceError, type DuckdbToCubeOptions, cubeToDuckdb, duckdbToCube, duckdbToDataset, openDuckdbNode };
@@ -0,0 +1,115 @@
1
+ import { arrowToCube, cubeToArrow } from '../chunk-IDTQZG4B.js';
2
+
3
+ // src/sources/duckdb.ts
4
+ var DuckdbSourceError = class extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ this.name = "DuckdbSourceError";
8
+ }
9
+ };
10
+ async function runQuery(conn, query) {
11
+ if (typeof conn.arrow === "function") {
12
+ return await conn.arrow(query);
13
+ }
14
+ if (typeof conn.arrowResult === "function") {
15
+ const res = await conn.arrowResult(query);
16
+ if (res && typeof res.arrow === "function") return await res.arrow();
17
+ return res;
18
+ }
19
+ throw new DuckdbSourceError(
20
+ "DuckDB connection has no arrow()/arrowResult() method; cannot fetch Arrow result"
21
+ );
22
+ }
23
+ async function duckdbToCube(connection, query, options = {}) {
24
+ let conn = connection;
25
+ let ownsConn = false;
26
+ if (options.connect) {
27
+ conn = await options.connect();
28
+ ownsConn = true;
29
+ }
30
+ let table;
31
+ try {
32
+ table = await runQuery(conn, query);
33
+ } catch (e) {
34
+ if (ownsConn && conn.close) await conn.close().catch(() => {
35
+ });
36
+ throw new DuckdbSourceError(`DuckDB query failed: ${e?.message ?? e}`);
37
+ }
38
+ if (ownsConn && conn.close) await conn.close().catch(() => {
39
+ });
40
+ if (!table) throw new DuckdbSourceError("DuckDB returned no result");
41
+ return arrowToCube(table, options);
42
+ }
43
+ async function duckdbToDataset(connection, query, options) {
44
+ const { toDataset } = await import('../cubeBuilder-BEGA4C5Y.js');
45
+ return toDataset(await duckdbToCube(connection, query, options));
46
+ }
47
+ async function openDuckdbNode(path = ":memory:") {
48
+ try {
49
+ const mod = await import('duckdb-async');
50
+ const db = await mod.createDb(path);
51
+ return await db.connect();
52
+ } catch {
53
+ throw new DuckdbSourceError(
54
+ "duckdb-async is not installed. Install it with `npm i duckdb-async` for Node usage."
55
+ );
56
+ }
57
+ }
58
+ function quoteIdent(name) {
59
+ return `"${name.replace(/"/g, '""')}"`;
60
+ }
61
+ async function registerArrowTable(conn, table, name, mode) {
62
+ if (mode === "view" && typeof conn.register === "function") {
63
+ await conn.register(name, table);
64
+ return;
65
+ }
66
+ if (typeof conn.insert_arrow_table === "function") {
67
+ await conn.insert_arrow_table(table, { name });
68
+ return;
69
+ }
70
+ if (mode === "view" && typeof conn.register === "function") {
71
+ await conn.register(name, table);
72
+ return;
73
+ }
74
+ if (typeof conn.run === "function") {
75
+ throw new DuckdbSourceError(
76
+ "DuckDB connection cannot ingest an Arrow Table: no register()/insert_arrow_table() method. Pass a duckdb-async or @duckdb/duckdb-wasm connection."
77
+ );
78
+ }
79
+ throw new DuckdbSourceError(
80
+ "DuckDB connection cannot ingest an Arrow Table: no register()/insert_arrow_table() method. Pass a duckdb-async or @duckdb/duckdb-wasm connection."
81
+ );
82
+ }
83
+ async function cubeToDuckdb(conn, obs, options = {}) {
84
+ const tableName = options.tableName ?? "observations";
85
+ const mode = options.mode ?? "view";
86
+ const table = cubeToArrow(obs);
87
+ try {
88
+ if (mode === "table") {
89
+ if (typeof conn.run === "function") {
90
+ const ident = quoteIdent(tableName);
91
+ const tempView = `__jsonstat_io_${tableName}_${Date.now()}`;
92
+ await registerArrowTable(conn, table, tempView, "view");
93
+ await conn.run(
94
+ `CREATE TABLE ${ident} AS SELECT * FROM ${quoteIdent(tempView)};`
95
+ );
96
+ if (typeof conn.run === "function") {
97
+ await conn.run(`DROP VIEW IF EXISTS ${quoteIdent(tempView)};`).catch(
98
+ () => {
99
+ }
100
+ );
101
+ }
102
+ return tableName;
103
+ }
104
+ }
105
+ await registerArrowTable(conn, table, tableName, mode);
106
+ return tableName;
107
+ } catch (e) {
108
+ if (e instanceof DuckdbSourceError) throw e;
109
+ throw new DuckdbSourceError(`DuckDB export failed: ${e?.message ?? e}`);
110
+ }
111
+ }
112
+
113
+ export { DuckdbSourceError, cubeToDuckdb, duckdbToCube, duckdbToDataset, openDuckdbNode };
114
+ //# sourceMappingURL=duckdb.js.map
115
+ //# sourceMappingURL=duckdb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/sources/duckdb.ts"],"names":[],"mappings":"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","file":"duckdb.js","sourcesContent":["/**\n * DuckDB adapter — `jsonstat-io/duckdb`.\n *\n * **Import:** runs a SQL query against DuckDB and funnels the result (as an\n * Arrow [`Table`]) through the Arrow hub\n * ([`arrowToCube`](../arrow/arrowToCube.ts)).\n *\n * **Export:** [`cubeToDuckdb`] registers an Arrow [`Table`] built from the\n * [`Observations`] IR into a DuckDB connection as a named table.\n *\n * Two optional peer backends are supported, picked automatically:\n *\n * - **Browser**: `@duckdb/duckdb-wasm` — instantiate via `@duckdb/duckdb-wasm`\n * and pass the connection (or a factory) to [`duckdbToCube`].\n * - **Node**: `duckdb-async` — a native binding; pass the connection.\n *\n * Both expose an `.arrowResult()` / `.arrow()` style API that yields an Arrow\n * Table. The adapter normalizes the two shapes.\n *\n * `@duckdb/duckdb-wasm` and `duckdb-async` are **optional peer dependencies**.\n */\n\nimport type { Observations } from \"../model/ir\";\nimport type { JsonStatDataset } from \"../model/jsonstat\";\nimport { arrowToCube, type ArrowToCubeOptions } from \"../arrow/arrowToCube\";\nimport { cubeToArrow } from \"../arrow/arrowFromCube\";\nimport type { Table } from \"apache-arrow\";\n\n// ---------------------------------------------------------------------------\n// Errors & types\n// ---------------------------------------------------------------------------\n\nexport class DuckdbSourceError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DuckdbSourceError\";\n }\n}\n\n/**\n * A minimal connection interface covering both duckdb-wasm and duckdb-async.\n * The adapter only requires a way to run a query and obtain an Arrow Table.\n */\nexport interface DuckdbConnection {\n /** Run a SQL query and return an Apache Arrow Table. */\n arrow(query: string): Promise<any>;\n /**\n * Register an Arrow Table under a view name (duckdb-async style). Optional:\n * the export path falls back to `insert_arrow_table` / `conn.register` if\n * this is absent.\n */\n register?(viewName: string, table: any): Promise<void>;\n /** DuckDB-wasm style: insert an Arrow Table into a named table. */\n insert_arrow_table?(table: any, options?: { name?: string }): Promise<void>;\n /** Run an arbitrary SQL statement (no Arrow result). */\n run?(query: string): Promise<unknown>;\n close?(): Promise<void>;\n}\n\nexport interface DuckdbToCubeOptions extends ArrowToCubeOptions {\n /**\n * A factory that returns a fresh connection. Useful for browser setups where\n * the wasm module must be instantiated lazily. If provided, takes precedence\n * over `connection` and is closed after use.\n */\n connect?: () => Promise<DuckdbConnection>;\n}\n\n// ---------------------------------------------------------------------------\n// Internal: normalize Arrow result extraction\n// ---------------------------------------------------------------------------\n\n/**\n * DuckDB bindings return Arrow tables via differently-named methods\n * (`arrowResult`, `arrow`, `all`+manual). Try the common ones in order.\n */\nasync function runQuery(conn: DuckdbConnection, query: string): Promise<any> {\n if (typeof (conn as any).arrow === \"function\") {\n return await (conn as any).arrow(query);\n }\n if (typeof (conn as any).arrowResult === \"function\") {\n const res = await (conn as any).arrowResult(query);\n // duckdb-wasm: result is either a Table or has .getAll() / .arrow()\n if (res && typeof res.arrow === \"function\") return await res.arrow();\n return res;\n }\n throw new DuckdbSourceError(\n \"DuckDB connection has no arrow()/arrowResult() method; cannot fetch Arrow result\",\n );\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Run a SQL query against DuckDB and convert the result to the\n * [`Observations`] IR via the Arrow hub.\n *\n * @param connectionOrFactory A [`DuckdbConnection`] or (via `options.connect`)\n * a factory creating one.\n * @param query SQL to execute.\n * @throws [`DuckdbSourceError`] on query or conversion failure.\n */\nexport async function duckdbToCube(\n connection: DuckdbConnection,\n query: string,\n options: DuckdbToCubeOptions = {},\n): Promise<Observations> {\n let conn: DuckdbConnection = connection;\n let ownsConn = false;\n if (options.connect) {\n conn = await options.connect();\n ownsConn = true;\n }\n\n let table: any;\n try {\n table = await runQuery(conn, query);\n } catch (e: any) {\n if (ownsConn && conn.close) await conn.close().catch(() => {});\n throw new DuckdbSourceError(`DuckDB query failed: ${e?.message ?? e}`);\n }\n\n if (ownsConn && conn.close) await conn.close().catch(() => {});\n if (!table) throw new DuckdbSourceError(\"DuckDB returned no result\");\n\n return arrowToCube(table, options);\n}\n\n/** Convenience: DuckDB query → JSON-stat [`Dataset`]. */\nexport async function duckdbToDataset(\n connection: DuckdbConnection,\n query: string,\n options?: DuckdbToCubeOptions,\n): Promise<JsonStatDataset> {\n const { toDataset } = await import(\"../core/cubeBuilder\");\n return toDataset(await duckdbToCube(connection, query, options));\n}\n\n/**\n * Helper for Node users of `duckdb-async`: create a connection from a\n * Database instance. Importing `duckdb-async` is lazy so browser bundles stay\n * lean.\n */\nexport async function openDuckdbNode(path = \":memory:\"): Promise<DuckdbConnection> {\n try {\n const mod: any = await import(\"duckdb-async\");\n const db = await mod.createDb(path);\n return (await db.connect()) as DuckdbConnection;\n } catch {\n throw new DuckdbSourceError(\n \"duckdb-async is not installed. Install it with `npm i duckdb-async` for Node usage.\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Export: Observations IR → DuckDB table\n// ---------------------------------------------------------------------------\n\nexport interface CubeToDuckdbOptions {\n /** Name of the target table/view to create. Defaults to `\"observations\"`. */\n tableName?: string;\n /**\n * `\"view\"` (default): registers the Arrow Table as a queryable view via\n * `conn.register` (cheap; the table is not copied). `\"table\"`: creates and\n * populates a physical table via DuckDB's `insert_arrow_table` / `CREATE\n * TABLE AS`.\n */\n mode?: \"view\" | \"table\";\n}\n\n/** Sanitize a table name into a valid DuckDB identifier (quoted). */\nfunction quoteIdent(name: string): string {\n return `\"${name.replace(/\"/g, '\"\"')}\"`;\n}\n\n/**\n * Register an Arrow [`Table`] into a DuckDB connection under a view/table name.\n *\n * Tries, in order: `conn.register(viewName, table)` (duckdb-async), then\n * `conn.insert_arrow_table(table, { name })` (duckdb-wasm), then a manual\n * `CREATE TABLE AS SELECT * FROM arrow_scan` fallback. Throws if none of the\n * registration paths are available on the connection.\n *\n * @internal\n */\nasync function registerArrowTable(\n conn: DuckdbConnection,\n table: Table,\n name: string,\n mode: \"view\" | \"table\",\n): Promise<void> {\n if (mode === \"view\" && typeof conn.register === \"function\") {\n await conn.register(name, table);\n return;\n }\n if (typeof conn.insert_arrow_table === \"function\") {\n // duckdb-wasm writes a physical table.\n await conn.insert_arrow_table(table, { name });\n return;\n }\n if (mode === \"view\" && typeof conn.register === \"function\") {\n await conn.register(name, table);\n return;\n }\n if (typeof conn.run === \"function\") {\n // Last-resort: register via the duckdb-async Connection.register, which is\n // already covered above; here we only reach if register is absent.\n throw new DuckdbSourceError(\n \"DuckDB connection cannot ingest an Arrow Table: no register()/insert_arrow_table() method. \" +\n \"Pass a duckdb-async or @duckdb/duckdb-wasm connection.\",\n );\n }\n throw new DuckdbSourceError(\n \"DuckDB connection cannot ingest an Arrow Table: no register()/insert_arrow_table() method. \" +\n \"Pass a duckdb-async or @duckdb/duckdb-wasm connection.\",\n );\n}\n\n/**\n * Write the [`Observations`](../model/ir.ts) IR into a DuckDB connection as a\n * named table (or view).\n *\n * The IR is first converted to an Arrow [`Table`] via [`cubeToArrow`], then\n * registered into the connection. All `jsonstat.*` schema/field metadata is\n * preserved on the Arrow schema, so a subsequent `SELECT * FROM <table>` →\n * [`arrowToCube`] round-trips the model.\n *\n * @returns The name of the created table/view.\n * @throws [`DuckdbSourceError`] if the connection cannot ingest Arrow tables.\n *\n * @example\n * ```ts\n * import { openDuckdbNode, cubeToDuckdb } from \"jsonstat-io/duckdb\";\n * const conn = await openDuckdbNode();\n * const name = await cubeToDuckdb(conn, observations, { tableName: \"sales\" });\n * const rows = await conn.arrow(`SELECT * FROM ${name} LIMIT 5`);\n * ```\n */\nexport async function cubeToDuckdb(\n conn: DuckdbConnection,\n obs: Observations,\n options: CubeToDuckdbOptions = {},\n): Promise<string> {\n const tableName = options.tableName ?? \"observations\";\n const mode = options.mode ?? \"view\";\n const table = cubeToArrow(obs);\n\n try {\n if (mode === \"table\") {\n // Materialize into a physical table: create empty then insert.\n if (typeof conn.run === \"function\") {\n const ident = quoteIdent(tableName);\n // DuckDB can register the Arrow table temporarily, then CTAS from it.\n const tempView = `__jsonstat_io_${tableName}_${Date.now()}`;\n await registerArrowTable(conn, table, tempView, \"view\");\n await conn.run(\n `CREATE TABLE ${ident} AS SELECT * FROM ${quoteIdent(tempView)};`,\n );\n // Best-effort drop of the temp view; ignore errors.\n if (typeof conn.run === \"function\") {\n await conn.run(`DROP VIEW IF EXISTS ${quoteIdent(tempView)};`).catch(\n () => {},\n );\n }\n return tableName;\n }\n }\n await registerArrowTable(conn, table, tableName, mode);\n return tableName;\n } catch (e: any) {\n if (e instanceof DuckdbSourceError) throw e;\n throw new DuckdbSourceError(`DuckDB export failed: ${e?.message ?? e}`);\n }\n}\n"]}
@@ -0,0 +1,117 @@
1
+ 'use strict';
2
+
3
+ var chunkPHLCWTHB_cjs = require('../chunk-PHLCWTHB.cjs');
4
+ var apacheArrow = require('apache-arrow');
5
+
6
+ var ParquetSourceError = class extends Error {
7
+ constructor(message) {
8
+ super(message);
9
+ this.name = "ParquetSourceError";
10
+ }
11
+ };
12
+ async function ensureParquetWasmInit(mod) {
13
+ const initialize = typeof mod.default === "function" ? mod.default : typeof mod.init === "function" ? mod.init : void 0;
14
+ if (initialize) await initialize();
15
+ }
16
+ async function loadParquetWasm() {
17
+ try {
18
+ const mod = await import('parquet-wasm');
19
+ await ensureParquetWasmInit(mod);
20
+ if (mod.default && typeof mod.default.readParquet === "function") return mod.default;
21
+ return mod;
22
+ } catch (e) {
23
+ throw new ParquetSourceError(
24
+ "parquet-wasm is not installed. Install it with `npm i parquet-wasm` to read Parquet files."
25
+ );
26
+ }
27
+ }
28
+ async function parquetToCube(bytes, options = {}) {
29
+ if (options.init) await options.init();
30
+ const wasm = await loadParquetWasm();
31
+ let wasmTable;
32
+ try {
33
+ wasmTable = wasm.readParquet(bytes);
34
+ } catch (e) {
35
+ throw new ParquetSourceError(`Failed to read Parquet: ${e?.message ?? e}`);
36
+ }
37
+ if (!wasmTable) throw new ParquetSourceError("parquet-wasm returned no table");
38
+ const ipc = wasmTable.intoIPCStream();
39
+ const table = apacheArrow.tableFromIPC(ipc);
40
+ return chunkPHLCWTHB_cjs.arrowToCube(table, options);
41
+ }
42
+ async function parquetToDataset(bytes, options) {
43
+ const { toDataset } = await import('../cubeBuilder-ZU76VVEX.cjs');
44
+ return toDataset(await parquetToCube(bytes, options));
45
+ }
46
+ var COMPRESSION_CODEC_KEYS = [
47
+ "uncompressed",
48
+ "snappy",
49
+ "gzip",
50
+ "brotli",
51
+ "lz4",
52
+ "lz4_raw",
53
+ "zstd",
54
+ "lzo"
55
+ ];
56
+ var COMPRESSION_CODEC_SET = new Set(COMPRESSION_CODEC_KEYS);
57
+ function buildWriterProperties(wasm, codec) {
58
+ if (!codec) return void 0;
59
+ const key = codec.toLowerCase();
60
+ if (!COMPRESSION_CODEC_SET.has(key)) {
61
+ throw new ParquetSourceError(
62
+ `Unknown compression codec "${codec}". Valid (case-insensitive): ${[...COMPRESSION_CODEC_KEYS].join(", ")}.`
63
+ );
64
+ }
65
+ const Compression = wasm.Compression;
66
+ const WriterPropertiesBuilder = wasm.WriterPropertiesBuilder;
67
+ if (!Compression || !WriterPropertiesBuilder) {
68
+ throw new ParquetSourceError(
69
+ `Cannot apply compression "${codec}": this parquet-wasm build does not export WriterPropertiesBuilder/Compression. Omit the \`compression\` option to use the default codec.`
70
+ );
71
+ }
72
+ const enumKey = key.toUpperCase();
73
+ if (!(enumKey in Compression)) {
74
+ throw new ParquetSourceError(
75
+ `Compression codec "${codec}" is not available in this parquet-wasm build. Omit the \`compression\` option to use the default codec.`
76
+ );
77
+ }
78
+ return new WriterPropertiesBuilder().setCompression(Compression[enumKey]).build();
79
+ }
80
+ async function loadParquetWriter() {
81
+ try {
82
+ const mod = await import('parquet-wasm');
83
+ await ensureParquetWasmInit(mod);
84
+ if (mod.default && typeof mod.default.writeParquet === "function") return mod.default;
85
+ return mod;
86
+ } catch {
87
+ throw new ParquetSourceError(
88
+ "parquet-wasm is not installed. Install it with `npm i parquet-wasm` to write Parquet files."
89
+ );
90
+ }
91
+ }
92
+ async function arrowToParquet(table, options = {}) {
93
+ if (options.init) await options.init();
94
+ const wasm = await loadParquetWriter();
95
+ try {
96
+ const writerProps = buildWriterProperties(wasm, options.compression);
97
+ const ipc = apacheArrow.tableToIPC(table, "stream");
98
+ const wasmTable = wasm.Table.fromIPCStream(ipc);
99
+ const bytes = wasm.writeParquet(wasmTable, writerProps);
100
+ if (bytes instanceof Uint8Array) return bytes;
101
+ return new Uint8Array(bytes);
102
+ } catch (e) {
103
+ throw new ParquetSourceError(`Failed to write Parquet: ${e?.message ?? e}`);
104
+ }
105
+ }
106
+ async function cubeToParquet(obs, options = {}) {
107
+ const table = chunkPHLCWTHB_cjs.cubeToArrow(obs);
108
+ return arrowToParquet(table, options);
109
+ }
110
+
111
+ exports.ParquetSourceError = ParquetSourceError;
112
+ exports.arrowToParquet = arrowToParquet;
113
+ exports.cubeToParquet = cubeToParquet;
114
+ exports.parquetToCube = parquetToCube;
115
+ exports.parquetToDataset = parquetToDataset;
116
+ //# sourceMappingURL=parquet.cjs.map
117
+ //# sourceMappingURL=parquet.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/sources/parquet.ts"],"names":["tableFromIPC","arrowToCube","tableToIPC","cubeToArrow"],"mappings":"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","file":"parquet.cjs","sourcesContent":["/**\n * Parquet adapter — `jsonstat-io/parquet`.\n *\n * **Import:** reads a Parquet file (bytes) into an Arrow [`Table`] via\n * `parquet-wasm`, then funnels through the Arrow hub\n * ([`arrowToCube`](../arrow/arrowToCube.ts)).\n *\n * **Export:** [`cubeToParquet`] writes the [`Observations`] IR to a Parquet\n * file via `cubeToArrow` → `parquet-wasm` `writeParquet`.\n *\n * `parquet-wasm` is an **optional peer dependency** — it is imported lazily so\n * that consumers who never touch Parquet pay no bundle cost. If it is not\n * installed, calling [`parquetToCube`] / [`cubeToParquet`] throws a helpful\n * error.\n */\n\nimport type { Observations } from \"../model/ir\";\nimport type { JsonStatDataset } from \"../model/jsonstat\";\nimport { arrowToCube, type ArrowToCubeOptions } from \"../arrow/arrowToCube\";\nimport { cubeToArrow } from \"../arrow/arrowFromCube\";\nimport type { Table } from \"apache-arrow\";\nimport { tableToIPC, tableFromIPC } from \"apache-arrow\";\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class ParquetSourceError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ParquetSourceError\";\n }\n}\n\n// ---------------------------------------------------------------------------\n// Options\n// ---------------------------------------------------------------------------\n\nexport interface ParquetToCubeOptions extends ArrowToCubeOptions {\n /**\n * Async initializer for parquet-wasm (e.g. to set the WASM base URL in the\n * browser). If provided, it is awaited before reading. Defaults to a no-op.\n */\n init?: () => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------\n// Internal: lazy parquet-wasm loader\n// ---------------------------------------------------------------------------\n\n/**\n * Dynamically import parquet-wasm and ensure its WASM binary is instantiated.\n * Kept in a function so the import is only evaluated when a Parquet read is\n * actually requested.\n *\n * parquet-wasm's ESM build exports the WASM initializer (`__wbg_init`) as the\n * module's **default** export. Calling it with no argument makes it fetch and\n * instantiate `parquet_wasm_bg.wasm` relative to the module URL. It is\n * idempotent (early-returns once `wasm` is set), so calling it again on a build\n * that already initialized — e.g. the Node/CJS build, which may auto-init — is\n * safe. Without this call, `readParquet`/`writeParquet` throw because the\n * wasm-bindgen internals (e.g. `__wbindgen_add_to_stack_pointer`) are not yet\n * wired up.\n */\nasync function ensureParquetWasmInit(mod: any): Promise<void> {\n const initialize =\n typeof mod.default === \"function\"\n ? mod.default // ESM build: default export = __wbg_init\n : typeof mod.init === \"function\"\n ? mod.init // some bundles expose a named init()\n : undefined;\n if (initialize) await initialize();\n}\n\n/**\n * Dynamically import parquet-wasm, ensure the WASM binary is ready, and return\n * the object exposing `readParquet`.\n */\nasync function loadParquetWasm(): Promise<any> {\n try {\n const mod: any = await import(\"parquet-wasm\");\n await ensureParquetWasmInit(mod);\n // After init, the named exports (readParquet, Table, ...) are ready.\n if (mod.default && typeof mod.default.readParquet === \"function\") return mod.default;\n return mod;\n } catch (e) {\n throw new ParquetSourceError(\n \"parquet-wasm is not installed. Install it with `npm i parquet-wasm` to read Parquet files.\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/**\n * Read a Parquet file (as `Uint8Array` / `ArrayBuffer`) into the\n * [`Observations`] IR.\n *\n * @throws [`ParquetSourceError`] if parquet-wasm is missing or the file is invalid.\n */\nexport async function parquetToCube(\n bytes: Uint8Array | ArrayBuffer,\n options: ParquetToCubeOptions = {},\n): Promise<Observations> {\n if (options.init) await options.init();\n const wasm = await loadParquetWasm();\n let wasmTable: any;\n try {\n // parquet-wasm's readParquet returns its own Arrow Table (apache-arrow\n // interop via IPC), not the caller's apache-arrow Table.\n wasmTable = wasm.readParquet(bytes);\n } catch (e: any) {\n throw new ParquetSourceError(`Failed to read Parquet: ${e?.message ?? e}`);\n }\n if (!wasmTable) throw new ParquetSourceError(\"parquet-wasm returned no table\");\n\n // Bridge the dual-Arrow hazard: serialize via IPC (a format both copies\n // understand) and reconstruct with our apache-arrow `tableFromIPC`, exactly\n // as documented in the parquet-wasm README:\n // const arrowTable = tableFromIPC(wasmTable.intoIPCStream());\n const ipc = wasmTable.intoIPCStream();\n const table = tableFromIPC(ipc);\n return arrowToCube(table, options);\n}\n\n/** Convenience: Parquet bytes → JSON-stat [`Dataset`]. */\nexport async function parquetToDataset(\n bytes: Uint8Array | ArrayBuffer,\n options?: ParquetToCubeOptions,\n): Promise<JsonStatDataset> {\n const { toDataset } = await import(\"../core/cubeBuilder\");\n return toDataset(await parquetToCube(bytes, options));\n}\n\n// ---------------------------------------------------------------------------\n// Export: Observations IR → Parquet bytes\n// ---------------------------------------------------------------------------\n\nexport interface CubeToParquetOptions {\n /**\n * Async initializer for parquet-wasm (e.g. to set the WASM base URL in the\n * browser). If provided, it is awaited before writing. Defaults to a no-op.\n */\n init?: () => Promise<void>;\n /**\n * Compression codec. Falls back to parquet-wasm's default (Snappy) when\n * undefined. Friendly names (case-insensitive) accepted: `\"uncompressed\"`,\n * `\"snappy\"`, `\"gzip\"`, `\"brotli\"`, `\"lz4\"`, `\"lz4_raw\"`, `\"zstd\"`, `\"lzo\"`.\n * Codec availability depends on the parquet-wasm build flavor (e.g. Brotli\n * may be absent in slim builds); an unavailable codec surfaces as a\n * [`ParquetSourceError`].\n */\n compression?: string;\n}\n\n/**\n * Friendly codec name (lowercase) → parquet-wasm `Compression` enum key.\n *\n * The enum's *numeric* values are read off the loaded wasm module at runtime\n * (see [`buildWriterProperties`]) rather than hardcoded here, so the adapter\n * tracks upstream renumbering automatically. We only map names → enum keys.\n */\nconst COMPRESSION_CODEC_KEYS = [\n \"uncompressed\",\n \"snappy\",\n \"gzip\",\n \"brotli\",\n \"lz4\",\n \"lz4_raw\",\n \"zstd\",\n \"lzo\",\n] as const;\n\n/** Set of accepted codec names, for fast lowercase lookup + error messages. */\nconst COMPRESSION_CODEC_SET = new Set<string>(COMPRESSION_CODEC_KEYS);\n\n/**\n * Build a parquet-wasm `WriterProperties` for the requested codec, or return\n * `undefined` to let `writeParquet` use its default (Snappy).\n *\n * Reads the real `Compression` enum off the loaded wasm module — so we never\n * hardcode numeric values that could drift across parquet-wasm versions.\n *\n * @throws [`ParquetSourceError`] if the codec name is unknown, or if the wasm\n * build does not export `WriterPropertiesBuilder` / `Compression` / the\n * requested codec key.\n */\nfunction buildWriterProperties(wasm: any, codec: string | undefined): any {\n if (!codec) return undefined;\n const key = codec.toLowerCase();\n if (!COMPRESSION_CODEC_SET.has(key)) {\n throw new ParquetSourceError(\n `Unknown compression codec \"${codec}\". ` +\n `Valid (case-insensitive): ${[...COMPRESSION_CODEC_KEYS].join(\", \")}.`,\n );\n }\n const Compression: any = wasm.Compression;\n const WriterPropertiesBuilder: any = wasm.WriterPropertiesBuilder;\n if (!Compression || !WriterPropertiesBuilder) {\n throw new ParquetSourceError(\n `Cannot apply compression \"${codec}\": this parquet-wasm build does not ` +\n \"export WriterPropertiesBuilder/Compression. \" +\n \"Omit the `compression` option to use the default codec.\",\n );\n }\n const enumKey = key.toUpperCase();\n if (!(enumKey in Compression)) {\n throw new ParquetSourceError(\n `Compression codec \"${codec}\" is not available in this parquet-wasm ` +\n \"build. Omit the `compression` option to use the default codec.\",\n );\n }\n return new WriterPropertiesBuilder().setCompression(Compression[enumKey]).build();\n}\n\n/**\n * Resolve the parquet-wasm `writeParquet` entrypoint. Mirrors\n * [`loadParquetWasm`], but documented separately because the two bindings can\n * diverge across parquet-wasm versions.\n */\nasync function loadParquetWriter(): Promise<any> {\n try {\n const mod: any = await import(\"parquet-wasm\");\n await ensureParquetWasmInit(mod);\n if (mod.default && typeof mod.default.writeParquet === \"function\") return mod.default;\n return mod;\n } catch {\n throw new ParquetSourceError(\n \"parquet-wasm is not installed. Install it with `npm i parquet-wasm` to write Parquet files.\",\n );\n }\n}\n\n/**\n * Serialize an Arrow [`Table`] to Parquet bytes using `parquet-wasm`. Extracted\n * so [`cubeToParquet`] and the round-trip tests share one path.\n *\n * @internal\n */\nexport async function arrowToParquet(\n table: Table,\n options: CubeToParquetOptions = {},\n): Promise<Uint8Array> {\n if (options.init) await options.init();\n const wasm = await loadParquetWriter();\n try {\n // Resolve the codec to a real parquet-wasm WriterProperties instance.\n // parquet-wasm@0.6.x's writeParquet expects a WriterProperties built via\n // WriterPropertiesBuilder (NOT a plain {compression} options bag); passing\n // a plain object throws \"expected instance of WriterProperties\". When\n // `compression` is omitted we pass `undefined` so writeParquet falls back\n // to its own default (Snappy). See .idea/jsonstat-io-parquet-compression-plan.md.\n const writerProps = buildWriterProperties(wasm, options.compression);\n\n // Bridge the dual-Arrow hazard: parquet-wasm bundles its own copy of\n // apache-arrow, so an `instanceof` check against its internal `Table` fails\n // for our caller's `Table`. We serialize via IPC (a format both copies\n // understand) and reconstruct inside parquet-wasm's `Table`, exactly as\n // documented in the parquet-wasm README:\n // Table.fromIPCStream(tableToIPC(table, \"stream\"))\n const ipc = tableToIPC(table, \"stream\");\n const wasmTable = wasm.Table.fromIPCStream(ipc);\n const bytes = wasm.writeParquet(wasmTable, writerProps);\n\n // parquet-wasm returns a Uint8Array (node) or a WebAssembly.Memory-backed\n // view; normalize to Uint8Array in both runtimes.\n if (bytes instanceof Uint8Array) return bytes;\n return new Uint8Array(bytes);\n } catch (e: any) {\n throw new ParquetSourceError(`Failed to write Parquet: ${e?.message ?? e}`);\n }\n}\n\n/**\n * Write the [`Observations`](../model/ir.ts) IR to a Parquet file (bytes).\n *\n * The IR is first converted to an Arrow [`Table`] via [`cubeToArrow`], then\n * serialized to Parquet via `parquet-wasm`'s `writeParquet`. All `jsonstat.*`\n * schema/field metadata is preserved, so the result round-trips through\n * [`parquetToCube`].\n *\n * @returns A `Uint8Array` of the Parquet file.\n * @throws [`ParquetSourceError`] if parquet-wasm is missing or the write fails.\n *\n * @example\n * ```ts\n * import { cubeToParquet } from \"jsonstat-io/parquet\";\n * const bytes = await cubeToParquet(observations);\n * ```\n */\nexport async function cubeToParquet(\n obs: Observations,\n options: CubeToParquetOptions = {},\n): Promise<Uint8Array> {\n const table = cubeToArrow(obs);\n return arrowToParquet(table, options);\n}\n"]}
@@ -0,0 +1,83 @@
1
+ import { O as Observations } from '../ir-BArfNxo-.cjs';
2
+ import { J as JsonStatDataset } from '../jsonstat-BX4mBLci.cjs';
3
+ import { A as ArrowToCubeOptions } from '../arrowToCube-BdRWZ5oG.cjs';
4
+ import { Table } from 'apache-arrow';
5
+
6
+ /**
7
+ * Parquet adapter — `jsonstat-io/parquet`.
8
+ *
9
+ * **Import:** reads a Parquet file (bytes) into an Arrow [`Table`] via
10
+ * `parquet-wasm`, then funnels through the Arrow hub
11
+ * ([`arrowToCube`](../arrow/arrowToCube.ts)).
12
+ *
13
+ * **Export:** [`cubeToParquet`] writes the [`Observations`] IR to a Parquet
14
+ * file via `cubeToArrow` → `parquet-wasm` `writeParquet`.
15
+ *
16
+ * `parquet-wasm` is an **optional peer dependency** — it is imported lazily so
17
+ * that consumers who never touch Parquet pay no bundle cost. If it is not
18
+ * installed, calling [`parquetToCube`] / [`cubeToParquet`] throws a helpful
19
+ * error.
20
+ */
21
+
22
+ declare class ParquetSourceError extends Error {
23
+ constructor(message: string);
24
+ }
25
+ interface ParquetToCubeOptions extends ArrowToCubeOptions {
26
+ /**
27
+ * Async initializer for parquet-wasm (e.g. to set the WASM base URL in the
28
+ * browser). If provided, it is awaited before reading. Defaults to a no-op.
29
+ */
30
+ init?: () => Promise<void>;
31
+ }
32
+ /**
33
+ * Read a Parquet file (as `Uint8Array` / `ArrayBuffer`) into the
34
+ * [`Observations`] IR.
35
+ *
36
+ * @throws [`ParquetSourceError`] if parquet-wasm is missing or the file is invalid.
37
+ */
38
+ declare function parquetToCube(bytes: Uint8Array | ArrayBuffer, options?: ParquetToCubeOptions): Promise<Observations>;
39
+ /** Convenience: Parquet bytes → JSON-stat [`Dataset`]. */
40
+ declare function parquetToDataset(bytes: Uint8Array | ArrayBuffer, options?: ParquetToCubeOptions): Promise<JsonStatDataset>;
41
+ interface CubeToParquetOptions {
42
+ /**
43
+ * Async initializer for parquet-wasm (e.g. to set the WASM base URL in the
44
+ * browser). If provided, it is awaited before writing. Defaults to a no-op.
45
+ */
46
+ init?: () => Promise<void>;
47
+ /**
48
+ * Compression codec. Falls back to parquet-wasm's default (Snappy) when
49
+ * undefined. Friendly names (case-insensitive) accepted: `"uncompressed"`,
50
+ * `"snappy"`, `"gzip"`, `"brotli"`, `"lz4"`, `"lz4_raw"`, `"zstd"`, `"lzo"`.
51
+ * Codec availability depends on the parquet-wasm build flavor (e.g. Brotli
52
+ * may be absent in slim builds); an unavailable codec surfaces as a
53
+ * [`ParquetSourceError`].
54
+ */
55
+ compression?: string;
56
+ }
57
+ /**
58
+ * Serialize an Arrow [`Table`] to Parquet bytes using `parquet-wasm`. Extracted
59
+ * so [`cubeToParquet`] and the round-trip tests share one path.
60
+ *
61
+ * @internal
62
+ */
63
+ declare function arrowToParquet(table: Table, options?: CubeToParquetOptions): Promise<Uint8Array>;
64
+ /**
65
+ * Write the [`Observations`](../model/ir.ts) IR to a Parquet file (bytes).
66
+ *
67
+ * The IR is first converted to an Arrow [`Table`] via [`cubeToArrow`], then
68
+ * serialized to Parquet via `parquet-wasm`'s `writeParquet`. All `jsonstat.*`
69
+ * schema/field metadata is preserved, so the result round-trips through
70
+ * [`parquetToCube`].
71
+ *
72
+ * @returns A `Uint8Array` of the Parquet file.
73
+ * @throws [`ParquetSourceError`] if parquet-wasm is missing or the write fails.
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * import { cubeToParquet } from "jsonstat-io/parquet";
78
+ * const bytes = await cubeToParquet(observations);
79
+ * ```
80
+ */
81
+ declare function cubeToParquet(obs: Observations, options?: CubeToParquetOptions): Promise<Uint8Array>;
82
+
83
+ export { type CubeToParquetOptions, ParquetSourceError, type ParquetToCubeOptions, arrowToParquet, cubeToParquet, parquetToCube, parquetToDataset };