Skip to content

Commit 76d8919

Browse files
author
Annie Zhang
authored
Add and export getSchema function (#363)
* Add and export getSchema function * more unit tests * handle type assertions outside of getSchema; simplify unit tests * move comment * use inferred instead of shouldCoerce; use input instead of source * aaand update tests too * simplification
1 parent 7862ecb commit 76d8919

File tree

3 files changed

+86
-12
lines changed

3 files changed

+86
-12
lines changed

src/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ export {
1010
isDatabaseClient,
1111
__table as applyDataTableOperations,
1212
getTypeValidator,
13-
inferSchema
13+
inferSchema,
14+
getSchema
1415
} from "./table.js";

src/table.js

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -617,18 +617,24 @@ export function coerceToType(value, type) {
617617
}
618618
}
619619

620+
export function getSchema(source) {
621+
const {columns} = source;
622+
let {schema} = source;
623+
if (!isQueryResultSetSchema(schema)) {
624+
schema = inferSchema(source, isQueryResultSetColumns(columns) ? columns : undefined);
625+
return {schema, inferred: true};
626+
}
627+
return {schema, inferred: false};
628+
}
629+
620630
// This function applies table cell operations to an in-memory table (array of
621631
// objects); it should be equivalent to the corresponding SQL query. TODO Use
622632
// DuckDBClient for data arrays, too, and then we wouldn’t need our own __table
623633
// function to do table operations on in-memory data?
624634
export function __table(source, operations) {
625635
const input = source;
626-
let {schema, columns} = source;
627-
let inferredSchema = false;
628-
if (!isQueryResultSetSchema(schema)) {
629-
schema = inferSchema(source, isQueryResultSetColumns(columns) ? columns : undefined);
630-
inferredSchema = true;
631-
}
636+
let {columns} = source;
637+
let {schema, inferred} = getSchema(source);
632638
// Combine column types from schema with user-selected types in operations
633639
const types = new Map(schema.map(({name, type}) => [name, type]));
634640
if (operations.types) {
@@ -640,7 +646,7 @@ export function __table(source, operations) {
640646
if (colIndex > -1) schema[colIndex] = {...schema[colIndex], type};
641647
}
642648
source = source.map(d => coerceRow(d, types, schema));
643-
} else if (inferredSchema) {
649+
} else if (inferred) {
644650
// Coerce data according to new schema, unless that happened due to
645651
// operations.types, above.
646652
source = source.map(d => coerceRow(d, types, schema));

test/table-test.js

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import {
33
getTypeValidator,
44
inferSchema,
55
makeQueryTemplate,
6-
__table
6+
__table,
7+
getSchema
78
} from "../src/table.js";
89
import assert from "assert";
910

@@ -805,13 +806,37 @@ describe("__table", () => {
805806
"b",
806807
"c"
807808
]);
808-
source.schema = [
809-
{name: "a", type: "integer", inferred: "integer"},
809+
assert.deepStrictEqual(__table(source, operations).schema, [
810+
{name: "nameA", type: "integer", inferred: "integer"},
811+
{name: "b", type: "integer", inferred: "integer"},
812+
{name: "c", type: "integer", inferred: "integer"}
813+
]);
814+
});
815+
816+
it("__table type assertions", () => {
817+
const operations = {
818+
...EMPTY_TABLE_DATA.operations,
819+
types: [{name: "a", type: "string"}]
820+
};
821+
const expected = [
822+
{a: "1", b: 2, c: 3},
823+
{a: "2", b: 4, c: 6},
824+
{a: "3", b: 6, c: 9}
825+
];
826+
expected.schema = [
827+
{name: "a", type: "string", inferred: "integer"},
810828
{name: "b", type: "integer", inferred: "integer"},
811829
{name: "c", type: "integer", inferred: "integer"}
812830
];
831+
assert.deepStrictEqual(__table(source, operations), expected);
832+
source.columns = ["a", "b", "c"];
833+
assert.deepStrictEqual(__table(source, operations).columns, [
834+
"a",
835+
"b",
836+
"c"
837+
]);
813838
assert.deepStrictEqual(__table(source, operations).schema, [
814-
{name: "nameA", type: "integer", inferred: "integer"},
839+
{name: "a", type: "string", inferred: "integer"},
815840
{name: "b", type: "integer", inferred: "integer"},
816841
{name: "c", type: "integer", inferred: "integer"}
817842
]);
@@ -1213,3 +1238,45 @@ describe("coerceToType", () => {
12131238
// Note: if type is "raw", coerceToType() will not be called. Instead, values
12141239
// will be returned from coerceRow().
12151240
});
1241+
1242+
describe("getSchema", () => {
1243+
let source;
1244+
1245+
beforeEach(() => {
1246+
source = [
1247+
{a: 1, b: "foo"},
1248+
{a: 2, b: "bar"}
1249+
];
1250+
source.schema = [
1251+
{name: "a", type: "integer", inferred: "integer"},
1252+
{name: "b", type: "string", inferred: "string"}
1253+
];
1254+
});
1255+
1256+
1257+
it("respects schema from source, if one exists", () => {
1258+
const {schema, inferred} = getSchema(source);
1259+
assert.strictEqual(inferred, false);
1260+
assert.strictEqual(schema, source.schema);
1261+
});
1262+
1263+
it("infers schema if source has no schema", () => {
1264+
source.schema = undefined;
1265+
const {schema, inferred} = getSchema(source);
1266+
assert.strictEqual(inferred, true);
1267+
assert.deepStrictEqual(schema,[
1268+
{name: "a", type: "integer", inferred: "integer"},
1269+
{name: "b", type: "string", inferred: "string"}
1270+
]);
1271+
});
1272+
1273+
it("infers schema if schema is invalid", () => {
1274+
source.schema = ["number"];
1275+
const {schema, inferred} = getSchema(source);
1276+
assert.strictEqual(inferred, true);
1277+
assert.deepStrictEqual(schema,[
1278+
{name: "a", type: "integer", inferred: "integer"},
1279+
{name: "b", type: "string", inferred: "string"}
1280+
]);
1281+
});
1282+
});

0 commit comments

Comments
 (0)