Skip to content

Commit c044d96

Browse files
authored
[TS] schema() takes an object (#4273)
# Description of Changes Implements the rest of the casing proposal. # Expected complexity level and risk <!-- How complicated do you think these changes are? Grade on a scale from 1 to 5, where 1 is a trivial change, and 5 is a deep-reaching and complex change. This complexity rating applies not only to the complexity apparent in the diff, but also to its interactions with existing and future code. If you answered more than a 2, explain what is complex about the PR, and what other components it interacts with in potentially concerning ways. --> # Testing <!-- Describe any testing you've done, and any testing you'd like your reviewers to do, so that you're confident that all the changes work as expected! --> - [ ] <!-- maybe a test you want to do --> - [ ] <!-- maybe a test you want a reviewer to do, so they can check it off when they're satisfied. -->
1 parent bba6f89 commit c044d96

88 files changed

Lines changed: 1008 additions & 880 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/bindings-typescript/src/lib/query.ts

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,28 @@ import { ConnectionId } from './connection_id';
22
import { Identity } from './identity';
33
import type { ColumnIndex, IndexColumns, IndexOpts } from './indexes';
44
import type { UntypedSchemaDef } from './schema';
5-
import type { TableSchema } from './table_schema';
5+
import type { UntypedTableSchema } from './table_schema';
66
import type {
77
ColumnBuilder,
88
ColumnMetadata,
99
RowBuilder,
1010
TypeBuilder,
1111
} from './type_builders';
12+
import type { Values } from './type_util';
1213

1314
/**
1415
* Helper to get the set of table names.
1516
*/
16-
export type TableNames<SchemaDef extends UntypedSchemaDef> =
17-
SchemaDef['tables'][number]['name'] & string;
17+
export type TableNames<SchemaDef extends UntypedSchemaDef> = Values<
18+
SchemaDef['tables']
19+
>['accessorName'] &
20+
string;
1821

1922
/** helper: pick the table def object from the schema by its name */
2023
export type TableDefByName<
2124
SchemaDef extends UntypedSchemaDef,
2225
Name extends TableNames<SchemaDef>,
23-
> = Extract<SchemaDef['tables'][number], { name: Name }>;
26+
> = Extract<Values<SchemaDef['tables']>, { accessorName: Name }>;
2427

2528
// internal only — NOT exported.
2629
// This is how we make sure queries are only created with our helpers.
@@ -105,7 +108,7 @@ class SemijoinImpl<TableDef extends TypedTableDef>
105108
readonly filterQuery: FromBuilder<any>,
106109
readonly joinCondition: BooleanExpr<any>
107110
) {
108-
if (sourceQuery.table.name === filterQuery.table.name) {
111+
if (sourceQuery.table.sourceName === filterQuery.table.sourceName) {
109112
// TODO: Handle aliasing properly instead of just forbidding it.
110113
throw new Error('Cannot semijoin a table to itself');
111114
}
@@ -129,8 +132,8 @@ class SemijoinImpl<TableDef extends TypedTableDef>
129132
toSql(): string {
130133
const left = this.filterQuery;
131134
const right = this.sourceQuery;
132-
const leftTable = quoteIdentifier(left.table.name);
133-
const rightTable = quoteIdentifier(right.table.name);
135+
const leftTable = quoteIdentifier(left.table.sourceName);
136+
const rightTable = quoteIdentifier(right.table.sourceName);
134137
let sql = `SELECT ${rightTable}.* FROM ${leftTable} JOIN ${rightTable} ON ${booleanExprToSql(this.joinCondition)}`;
135138

136139
const clauses: string[] = [];
@@ -212,8 +215,9 @@ class FromBuilder<TableDef extends TypedTableDef>
212215
}
213216

214217
export type QueryBuilder<SchemaDef extends UntypedSchemaDef> = {
215-
readonly [Tbl in SchemaDef['tables'][number] as Tbl['accessorName']]: TableRef<Tbl> &
216-
From<Tbl>;
218+
readonly [Tbl in Values<
219+
SchemaDef['tables']
220+
> as Tbl['accessorName']]: TableRef<Tbl> & From<Tbl>;
217221
} & {};
218222

219223
/**
@@ -222,7 +226,7 @@ export type QueryBuilder<SchemaDef extends UntypedSchemaDef> = {
222226
*/
223227
export type TableRef<TableDef extends TypedTableDef> = Readonly<{
224228
type: 'table';
225-
name: TableDef['name'];
229+
sourceName: TableDef['sourceName'];
226230
accessorName: string;
227231
cols: RowExpr<TableDef>;
228232
indexedCols: IndexedRowExpr<TableDef>;
@@ -239,7 +243,7 @@ class TableRefImpl<TableDef extends TypedTableDef>
239243
{
240244
readonly [QueryBrand] = true;
241245
readonly type = 'table' as const;
242-
name: string;
246+
sourceName: string;
243247
accessorName: string;
244248
cols: RowExpr<TableDef>;
245249
indexedCols: IndexedRowExpr<TableDef>;
@@ -258,7 +262,7 @@ class TableRefImpl<TableDef extends TypedTableDef>
258262
return (this.tableDef as any).constraints;
259263
}
260264
constructor(tableDef: TableDef) {
261-
this.name = tableDef.name;
265+
this.sourceName = tableDef.sourceName;
262266
this.accessorName = tableDef.accessorName;
263267
this.cols = createRowExpr(tableDef);
264268
// this.indexedCols = createIndexedRowExpr(tableDef, this.cols);
@@ -319,7 +323,7 @@ export function makeQueryBuilder<SchemaDef extends UntypedSchemaDef>(
319323
schema: SchemaDef
320324
): QueryBuilder<SchemaDef> {
321325
const qb = Object.create(null) as QueryBuilder<SchemaDef>;
322-
for (const table of schema.tables) {
326+
for (const table of Object.values(schema.tables)) {
323327
const ref = createTableRefFromDef(
324328
table as TableDefByName<SchemaDef, TableNames<SchemaDef>>
325329
);
@@ -337,7 +341,7 @@ function createRowExpr<TableDef extends TypedTableDef>(
337341
>) {
338342
const columnBuilder = tableDef.columns[columnName];
339343
const column = new ColumnExpression<TableDef, typeof columnName>(
340-
tableDef.name,
344+
tableDef.sourceName,
341345
columnName,
342346
columnBuilder.typeBuilder.algebraicType as InferSpacetimeTypeOfColumn<
343347
TableDef,
@@ -354,7 +358,7 @@ function renderSelectSqlWithJoins<Table extends TypedTableDef>(
354358
where?: BooleanExpr<Table>,
355359
extraClauses: readonly string[] = []
356360
): string {
357-
const quotedTable = quoteIdentifier(table.name);
361+
const quotedTable = quoteIdentifier(table.sourceName);
358362
const sql = `SELECT * FROM ${quotedTable}`;
359363
const clauses: string[] = [];
360364
if (where) clauses.push(booleanExprToSql(where));
@@ -372,16 +376,14 @@ export type TypedTableDef<
372376
ColumnBuilder<any, any, ColumnMetadata<any>>
373377
> = Record<string, ColumnBuilder<any, any, ColumnMetadata<any>>>,
374378
> = {
375-
name: string;
379+
sourceName: string;
376380
accessorName: string;
377381
columns: Columns;
378382
indexes: readonly IndexOpts<any>[];
379383
rowType: RowBuilder<Columns>['algebraicType']['value'];
380384
};
381385

382-
export type TableSchemaAsTableDef<
383-
TSchema extends TableSchema<any, any, readonly any[]>,
384-
> = {
386+
export type TableSchemaAsTableDef<TSchema extends UntypedTableSchema> = {
385387
name: TSchema['tableName'];
386388
columns: TSchema['rowType']['row'];
387389
indexes: TSchema['idxs'];
@@ -435,13 +437,13 @@ export class ColumnExpression<
435437
> {
436438
readonly type = 'column' as const;
437439
readonly column: ColumnName;
438-
readonly table: TableDef['name'];
440+
readonly table: TableDef['sourceName'];
439441
// phantom: actual runtime value is undefined
440442
readonly tsValueType?: RowType<TableDef>[ColumnName];
441443
readonly spacetimeType: InferSpacetimeTypeOfColumn<TableDef, ColumnName>;
442444

443445
constructor(
444-
table: TableDef['name'],
446+
table: TableDef['sourceName'],
445447
column: ColumnName,
446448
spacetimeType: InferSpacetimeTypeOfColumn<TableDef, ColumnName>
447449
) {

crates/bindings-typescript/src/lib/schema.ts

Lines changed: 32 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import type RawModuleDefV10Section from './autogen/raw_module_def_v_10_section_type';
99
import type RawModuleDefV10 from './autogen/raw_module_def_v_10_type';
1010
import type RawScopedTypeNameV10 from './autogen/raw_scoped_type_name_v_10_type';
11+
import type RawTableDefV10 from './autogen/raw_table_def_v_10_type';
1112
import type { UntypedIndex } from './indexes';
1213
import type { UntypedTableDef } from './table';
1314
import type { UntypedTableSchema } from './table_schema';
@@ -27,62 +28,69 @@ import {
2728
type RowObj,
2829
type VariantsObj,
2930
} from './type_builders';
30-
import type { CamelCase } from './type_util';
31+
import type { CamelCase, Values } from './type_util';
3132
import { toCamelCase } from './util';
3233

33-
export type TableNamesOf<S extends UntypedSchemaDef> =
34-
S['tables'][number]['name'];
34+
export type TableNamesOf<S extends UntypedSchemaDef> = Values<
35+
S['tables']
36+
>['accessorName'];
3537

3638
/**
3739
* An untyped representation of the database schema.
3840
*/
3941
export type UntypedSchemaDef = {
40-
tables: readonly UntypedTableDef[];
42+
tables: Record<string, UntypedTableDef>;
4143
};
4244

4345
/**
4446
* Helper type to convert an array of TableSchema into a schema definition
4547
*/
46-
export interface TablesToSchema<T extends readonly UntypedTableSchema[]>
48+
export interface TablesToSchema<T extends Record<string, UntypedTableSchema>>
4749
extends UntypedSchemaDef {
4850
tables: {
49-
readonly [i in keyof T]: TableToSchema<T[i]>;
51+
readonly [AccName in keyof T & string]: TableToSchema<AccName, T[AccName]>;
5052
};
5153
}
5254

53-
export interface TableToSchema<T extends UntypedTableSchema>
54-
extends UntypedTableDef {
55-
name: T['tableName'];
56-
accessorName: CamelCase<T['tableName']>;
55+
export interface TableToSchema<
56+
AccName extends string,
57+
T extends UntypedTableSchema,
58+
> extends UntypedTableDef {
59+
accessorName: CamelCase<AccName>;
5760
columns: T['rowType']['row'];
5861
rowType: T['rowSpacetimeType'];
5962
indexes: T['idxs'];
6063
constraints: T['constraints'];
6164
}
6265

63-
export function tablesToSchema<const T extends readonly UntypedTableSchema[]>(
64-
ctx: ModuleContext,
65-
tables: T
66-
): TablesToSchema<T> {
66+
export function tablesToSchema<
67+
const T extends Record<string, UntypedTableSchema>,
68+
>(ctx: ModuleContext, tables: T): TablesToSchema<T> {
6769
return {
68-
tables: tables.map(schema =>
69-
tableToSchema(ctx, schema)
70+
tables: Object.fromEntries(
71+
Object.entries(tables).map(([accName, schema]) => [
72+
accName,
73+
tableToSchema(accName, schema, schema.tableDef(ctx, accName)),
74+
])
7075
) as TablesToSchema<T>['tables'],
7176
};
7277
}
7378

74-
function tableToSchema<T extends UntypedTableSchema>(
75-
ctx: ModuleContext,
76-
schema: T
77-
): TableToSchema<T> {
79+
export function tableToSchema<
80+
AccName extends string,
81+
const T extends UntypedTableSchema,
82+
>(
83+
accName: AccName,
84+
schema: T,
85+
tableDef: Infer<typeof RawTableDefV10>
86+
): TableToSchema<AccName, T> {
7887
const getColName = (i: number) =>
7988
schema.rowType.algebraicType.value.elements[i].name;
80-
const tableDef = schema.tableDef(ctx);
8189

8290
type AllowedCol = keyof T['rowType']['row'] & string;
8391
return {
84-
name: schema.tableName,
85-
accessorName: toCamelCase(schema.tableName as T['tableName']),
92+
sourceName: schema.tableName ?? accName,
93+
accessorName: toCamelCase(accName),
8694
columns: schema.rowType.row, // typed as T[i]['rowType']['row'] under TablesToSchema<T>
8795
rowType: schema.rowSpacetimeType,
8896
constraints: tableDef.constraints.map(c => ({
@@ -108,6 +116,7 @@ function tableToSchema<T extends UntypedTableSchema>(
108116
columns: columnIds.map(getColName),
109117
};
110118
}) as T['idxs'],
119+
tableDef,
111120
};
112121
}
113122

0 commit comments

Comments
 (0)