Skip to content

Commit 366bfb0

Browse files
committed
support Apache Arrow for table cells
1 parent 0035eb7 commit 366bfb0

File tree

5 files changed

+38
-10
lines changed

5 files changed

+38
-10
lines changed

src/dependencies.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export const sql = dependency("sql.js", "1.7.0", "dist/sql-wasm.js");
1313
export const vega = dependency("vega", "5.22.1", "build/vega.min.js");
1414
export const vegalite = dependency("vega-lite", "5.5.0", "build/vega-lite.min.js");
1515
export const vegaliteApi = dependency("vega-lite-api", "5.0.0", "build/vega-lite-api.min.js");
16-
export const arrow = dependency("apache-arrow", "4.0.1", "Arrow.es2015.min.js");
16+
export const arrow4 = dependency("apache-arrow", "4.0.1", "Arrow.es2015.min.js");
17+
export const arrow10 = dependency("apache-arrow", "10.0.0", "Arrow.es2015.min.js");
1718
export const arquero = dependency("arquero", "4.8.8", "dist/arquero.min.js");
1819
export const topojson = dependency("topojson-client", "3.1.0", "dist/topojson-client.min.js");
1920
export const exceljs = dependency("exceljs", "4.3.0", "dist/exceljs.min.js");

src/fileAttachment.mjs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {autoType, csvParse, csvParseRows, tsvParse, tsvParseRows} from "d3-dsv";
2-
import {arrow, jszip, exceljs} from "./dependencies.mjs";
2+
import {arrow4, arrow10, jszip, exceljs} from "./dependencies.mjs";
33
import {requireDefault} from "./require.mjs";
44
import {SQLiteDatabaseClient} from "./sqlite.mjs";
55
import {Workbook} from "./xlsx.mjs";
@@ -56,9 +56,18 @@ export class AbstractFile {
5656
i.src = url;
5757
});
5858
}
59-
async arrow() {
60-
const [Arrow, response] = await Promise.all([requireDefault(arrow.resolve()), remote_fetch(this)]);
61-
return Arrow.Table.from(response);
59+
async arrow({version = 4} = {}) {
60+
switch (version) {
61+
case 4: {
62+
const [Arrow, response] = await Promise.all([requireDefault(arrow4.resolve()), remote_fetch(this)]);
63+
return Arrow.Table.from(response);
64+
}
65+
case 10: {
66+
const [Arrow, response] = await Promise.all([requireDefault(arrow10.resolve()), remote_fetch(this)]);
67+
return Arrow.tableFromIPC(response);
68+
}
69+
default: throw new Error(`unsupported arrow version: ${version}`);
70+
}
6271
}
6372
async sqlite() {
6473
return SQLiteDatabaseClient.open(remote_fetch(this));

src/index.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export {default as FileAttachments, AbstractFile} from "./fileAttachment.mjs";
22
export {default as Library} from "./library.mjs";
3-
export {makeQueryTemplate, loadDataSource, arrayIsPrimitive, isDataArray, isDatabaseClient} from "./table.mjs";
3+
export {makeQueryTemplate, loadDataSource, arrayIsPrimitive, isArrowTable, isDataArray, isDatabaseClient} from "./table.mjs";

src/library.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import svg from "./svg.mjs";
1717
import tex from "./tex.mjs";
1818
import vegalite from "./vegalite.mjs";
1919
import width from "./width.mjs";
20-
import {arquero, arrow, d3, graphviz, htl, inputs, lodash, plot, topojson} from "./dependencies.mjs";
20+
import {arquero, arrow4, d3, graphviz, htl, inputs, lodash, plot, topojson} from "./dependencies.mjs";
2121
import {__query} from "./table.mjs";
2222

2323
export default Object.assign(Object.defineProperties(function Library(resolver) {
@@ -40,7 +40,7 @@ export default Object.assign(Object.defineProperties(function Library(resolver)
4040
// https://observablehq.com/@observablehq/recommended-libraries
4141
_: () => require(lodash.resolve()),
4242
aq: () => require.alias({"apache-arrow": arrow.resolve()})(arquero.resolve()),
43-
Arrow: () => require(arrow.resolve()),
43+
Arrow: () => require(arrow4.resolve()), // TODO arrow10
4444
d3: () => require(d3.resolve()),
4545
Inputs: () => require(inputs.resolve()).then(Inputs => ({...Inputs, file: Inputs.fileOf(AbstractFile)})),
4646
L: () => leaflet(require),

src/table.mjs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@ export function isDatabaseClient(value, mode) {
2323
);
2424
}
2525

26+
// Returns true if the vaue is an Apache Arrow table.
27+
export function isArrowTable(value) {
28+
return (
29+
value &&
30+
value.schema &&
31+
Array.isArray(value.schema.fields) &&
32+
typeof value[Symbol.iterator] === "function"
33+
);
34+
}
35+
2636
// Returns true if the value is a typed array (for a single-column table), or if
2737
// it’s an array. In the latter case, the elements of the array must be
2838
// consistently typed: either plain objects or primitives or dates.
@@ -145,6 +155,7 @@ export const __query = Object.assign(
145155
source = await loadDataSource(await source, "table");
146156
if (isDatabaseClient(source)) return evaluateQuery(source, makeQueryTemplate(operations, source), invalidation);
147157
if (isDataArray(source)) return __table(source, operations);
158+
if (isArrowTable(source)) return __arrow(source, operations);
148159
if (!source) throw new Error("missing data source");
149160
throw new Error("invalid data source");
150161
},
@@ -164,7 +175,7 @@ export async function loadDataSource(source, mode) {
164175
case "text/csv": return source.csv({typed: true});
165176
case "text/tab-separated-values": return source.tsv({typed: true});
166177
case "application/json": return source.json();
167-
default: if (/\.arrow$/i.test(source.name)) return source.arrow(); // TODO apache-arrow@10
178+
default: if (/\.arrow$/i.test(source.name)) return source.arrow({version: 10});
168179
}
169180
}
170181
if (mode === "table" || mode === "sql") {
@@ -391,9 +402,16 @@ function likeOperand(operand) {
391402
return {...operand, value: `%${operand.value}%`};
392403
}
393404

405+
// This function applies table cell operations to an in-memory Apache Arrow
406+
// table; it should be equivalent to the corresponding SQL query.
407+
function __arrow(source, operations) {
408+
operations;
409+
return source; // TODO
410+
}
411+
394412
// This function applies table cell operations to an in-memory table (array of
395413
// objects); it should be equivalent to the corresponding SQL query.
396-
export function __table(source, operations) {
414+
function __table(source, operations) {
397415
const input = source;
398416
let {schema, columns} = source;
399417
let primitive = arrayIsPrimitive(source);

0 commit comments

Comments
 (0)