From 7814c55f1880577d6dec7b74b3af7c7fbc78100d Mon Sep 17 00:00:00 2001 From: Fernando Hurtado Date: Fri, 27 Sep 2024 20:36:36 +0200 Subject: [PATCH 1/7] feat: add runtime type checking --- prettier.config.js => .prettierrc.js | 0 .vscode/settings.json | 18 + packages/backend/package.json | 2 +- packages/backend/src/QueryEngine.ts | 18 +- .../src/execution/composeExecutionResults.ts | 18 +- .../backend/src/execution/execute.test.ts | 6 +- packages/backend/src/execution/execute.ts | 8 +- .../executors/PgExecutor/canExecute.test.ts | 14 +- .../queryBuilder/createAugmentedQuery.ts | 6 +- .../convertWhereToQueryProviderInput.test.ts | 13 +- .../convertWhereToQueryProviderInput.ts | 14 +- .../backend/src/query/iterateQuery.test.ts | 6 +- .../src/tests/benchmarks/bench.test.ts | 6 +- packages/backend/src/tests/compareStores.ts | 1 - packages/backend/src/tests/e2e/nx1.test.ts | 2 +- packages/backend/src/tests/e2e/nxm.test.ts | 4 +- .../backend/src/tests/e2e/payments.test.ts | 12 +- .../tests/e2e/store-with-customers.test.ts | 7 +- .../src/tests/e2e/store-with-films.test.ts | 6 +- .../arbitraries/ArbitraryQueryBuilder.ts | 26 +- .../arbitraries/arbitraryQuery.ts | 37 +- .../arbitraries/arbitrarySelect.ts | 4 +- .../properties/cardinalityMany.test.ts | 4 +- .../properties/cardinalityMaybe.test.ts | 4 +- .../properties/cardinalityOne.test.ts | 7 +- packages/backend/src/tests/queries.v2.ts | 2 +- packages/cli/package.json | 2 +- packages/cli/src/e2e.test.ts | 8 +- ....timestamp-1727430152478-724472fcd03ee.mjs | 0 packages/docs/package.json | 2 +- packages/handler-express/package.json | 2 +- packages/handler-next/package.json | 2 +- packages/introspect/package.json | 2 +- packages/introspect/src/e2e.test.ts | 4 +- packages/queries/package.json | 7 +- packages/queries/src/QueryBuilderError.ts | 8 +- packages/queries/src/col.ts | 4 +- packages/queries/src/index.ts | 1 - packages/queries/src/query.test.ts | 76 ++- packages/queries/src/query.ts | 633 ++++++------------ packages/queries/src/schema/getTableSchema.ts | 56 ++ .../src/schema/getTableSelectableColumns.ts | 6 +- packages/queries/src/types/AnyQuery.ts | 5 +- packages/queries/src/types/BinaryOp.ts | 12 +- packages/queries/src/types/Cardinality.ts | 10 +- packages/queries/src/types/ColumnValue.ts | 18 +- packages/queries/src/types/Include.ts | 8 - packages/queries/src/types/QueryResult.ts | 109 +-- packages/queries/src/types/RefOp.ts | 18 +- packages/queries/src/types/Select.ts | 3 + packages/queries/src/types/Where.ts | 7 +- packages/queries/src/types/WhereClause.ts | 15 +- packages/queries/src/types/types.ts | 43 +- packages/queries/src/util/hashQuery.ts | 4 +- .../validateNestedQueriesHaveAValidRefOp.ts | 7 +- packages/react/package.json | 2 +- packages/react/src/SynthqlQueryCache.ts | 13 - packages/react/src/synthqlQueryKey.ts | 12 +- packages/react/src/useSynthql.test.tsx | 40 +- packages/react/src/useSynthql.ts | 30 +- .../react/src/useSynthqlExamples.test.tsx | 9 +- packages/ui/package.json | 2 +- scripts/compile-executable-examples.cjs | 2 +- yarn.lock | 5 + 64 files changed, 635 insertions(+), 797 deletions(-) rename prettier.config.js => .prettierrc.js (100%) create mode 100644 .vscode/settings.json create mode 100644 packages/cli/vite.config.ts.timestamp-1727430152478-724472fcd03ee.mjs create mode 100644 packages/queries/src/schema/getTableSchema.ts delete mode 100644 packages/queries/src/types/Include.ts delete mode 100644 packages/react/src/SynthqlQueryCache.ts diff --git a/prettier.config.js b/.prettierrc.js similarity index 100% rename from prettier.config.js rename to .prettierrc.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..c886d76b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,18 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.tsserver.experimental.enableProjectDiagnostics": true, + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.organizeImports": "always" + }, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "[typescript]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + }, + "[json]": { + "editor.defaultFormatter": "esbenp.prettier-vscode" + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index 9f25080b..ef995fac 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -24,7 +24,7 @@ "typecheck": "tsc", "checks": "yarn vitest run && yarn tsc", "publish:minor": "yarn publish --access public --no-git-tag-version", - "format": "yarn prettier --config ../../prettier.config.js --write ./src/", + "format": "yarn prettier --config ../../.prettierrc.js --write ./src/", "benchmarks": "yarn vitest run src/tests/benchmarks/bench.test.ts" }, "dependencies": { diff --git a/packages/backend/src/QueryEngine.ts b/packages/backend/src/QueryEngine.ts index a09c496c..0866d62e 100644 --- a/packages/backend/src/QueryEngine.ts +++ b/packages/backend/src/QueryEngine.ts @@ -1,14 +1,14 @@ -import { Pool } from 'pg'; import { Query, QueryResult, Table } from '@synthql/queries'; -import { composeQuery } from './execution/executors/PgExecutor/composeQuery'; +import { Pool } from 'pg'; import { QueryPlan, collectLast } from '.'; import { QueryProvider } from './QueryProvider'; +import { SynthqlError } from './SynthqlError'; import { execute } from './execution/execute'; -import { QueryExecutor } from './execution/types'; -import { QueryProviderExecutor } from './execution/executors/QueryProviderExecutor'; import { PgExecutor } from './execution/executors/PgExecutor'; +import { composeQuery } from './execution/executors/PgExecutor/composeQuery'; +import { QueryProviderExecutor } from './execution/executors/QueryProviderExecutor'; +import { QueryExecutor } from './execution/types'; import { generateLast } from './util/generators/generateLast'; -import { SynthqlError } from './SynthqlError'; export interface QueryEngineProps { /** @@ -113,7 +113,7 @@ export class QueryEngine { returnLastOnly?: boolean; }, ): AsyncGenerator> { - const gen = execute(query, { + const gen = execute(query, { executors: this.executors, defaultSchema: opts?.schema ?? this.schema, prependSql: this.prependSql, @@ -143,7 +143,7 @@ export class QueryEngine { ): Promise> { return await collectLast( generateLast( - execute(query, { + execute(query, { executors: this.executors, defaultSchema: opts?.schema ?? this.schema, prependSql: this.prependSql, @@ -152,7 +152,9 @@ export class QueryEngine { ); } - compile(query: T extends Query ? T : never): { + compile( + query: T, + ): { sql: string; params: any[]; } { diff --git a/packages/backend/src/execution/composeExecutionResults.ts b/packages/backend/src/execution/composeExecutionResults.ts index b0ea7505..cacc322d 100644 --- a/packages/backend/src/execution/composeExecutionResults.ts +++ b/packages/backend/src/execution/composeExecutionResults.ts @@ -1,3 +1,4 @@ +import { Value } from '@sinclair/typebox/value'; import { AnyDB, AnyTable, QueryResult } from '@synthql/queries'; import { applyCardinality } from '../query/applyCardinality'; import { assertHasKey } from '../util/asserts/assertHasKey'; @@ -13,10 +14,25 @@ export function composeExecutionResults( composeExecutionResultsRecursively(node, queryResult); } - return applyCardinality( + const result = applyCardinality( queryResult, tree.root.inputQuery.cardinality ?? 'many', ) as QueryResult; + + const schema = tree.root.inputQuery.schema; + if (schema) { + const error = Value.Errors(schema, [], result).First(); + if (error) { + const lines = [ + `${error.message} at path: ${error.path}`, + `Value: ${JSON.stringify(error.value)}`, + `Schema: ${JSON.stringify(error.schema, null, 2)}`, + ]; + throw new Error(lines.join('\n')); + } + } + + return result; } function composeExecutionResultsRecursively( diff --git a/packages/backend/src/execution/execute.test.ts b/packages/backend/src/execution/execute.test.ts index cb277e28..7bfd3d24 100644 --- a/packages/backend/src/execution/execute.test.ts +++ b/packages/backend/src/execution/execute.test.ts @@ -217,7 +217,7 @@ describe('execute', () => { .one(); const result = await collectLast( - execute(q, { + execute(q, { executors: [new QueryProviderExecutor([actorProvider])], defaultSchema, }), @@ -247,7 +247,7 @@ describe('execute', () => { const q = findFilmWithRating(1); const result = await collectLast( - execute(q, { + execute(q, { executors: [ new QueryProviderExecutor([ filmProvider, @@ -269,7 +269,7 @@ describe('execute', () => { const q2 = findFilmWithRating(2); const result2 = await collectLast( - execute(q2, { + execute(q2, { executors: [ new QueryProviderExecutor([ filmProvider, diff --git a/packages/backend/src/execution/execute.ts b/packages/backend/src/execution/execute.ts index c5b95da2..eb0418e2 100644 --- a/packages/backend/src/execution/execute.ts +++ b/packages/backend/src/execution/execute.ts @@ -1,7 +1,7 @@ import { Query, QueryResult } from '@synthql/queries'; import { composeExecutionResults } from './composeExecutionResults'; -import { createExecutionPlan } from './planning/createExecutionPlan'; import { executePlan } from './execution/executePlan'; +import { createExecutionPlan } from './planning/createExecutionPlan'; import { QueryExecutor } from './types'; export interface ExecuteProps { @@ -33,13 +33,13 @@ export interface ExecuteProps { * We need to compose them into a single result. * */ -export async function* execute>( +export async function* execute( query: TQuery, props: ExecuteProps, -): AsyncGenerator> { +): AsyncGenerator> { const plan = createExecutionPlan(query, props); for await (const resultTree of executePlan(plan, props)) { - yield composeExecutionResults(resultTree); + yield composeExecutionResults(resultTree) as QueryResult; } } diff --git a/packages/backend/src/execution/executors/PgExecutor/canExecute.test.ts b/packages/backend/src/execution/executors/PgExecutor/canExecute.test.ts index 636eceb6..efa8798e 100644 --- a/packages/backend/src/execution/executors/PgExecutor/canExecute.test.ts +++ b/packages/backend/src/execution/executors/PgExecutor/canExecute.test.ts @@ -1,13 +1,13 @@ +import { col } from '@synthql/queries'; +import { describe, expect, test } from 'vitest'; +import { PgExecutor } from '.'; import { - filmActor, actor, - inventory, film, + filmActor, + inventory, store, } from '../../../tests/queries.v2'; -import { describe, expect, test } from 'vitest'; -import { col } from '@synthql/queries'; -import { PgExecutor } from '.'; import { pool } from '../../../tests/queryEngine'; describe('PgExecutor', () => { @@ -43,12 +43,12 @@ describe('PgExecutor', () => { .where({ store_id: { in: [1] } }) .one(); - expect(executor.canExecute(q)).toEqual({ + expect(executor.canExecute(q)).toMatchObject({ query: { ...q, include: { inventories: { ...inventories, include: {} } }, }, - remaining: [inventories.include.film], + remaining: [inventories.include?.film], }); }); }); diff --git a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/createAugmentedQuery.ts b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/createAugmentedQuery.ts index 720285eb..42b1654e 100644 --- a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/createAugmentedQuery.ts +++ b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/createAugmentedQuery.ts @@ -1,9 +1,9 @@ import { AnyDB, AnyQuery, Where, isRefOp } from '@synthql/queries'; import { collectFromQuery } from '../../../../query/collectFromQuery'; +import { ColumnRef } from '../../../../refs/ColumnRef'; +import { TableRef } from '../../../../refs/TableRef'; import { SelectionColumn } from './SelectionColumn'; import { SelectionJsonbAgg } from './SelectionJsonbAgg'; -import { TableRef } from '../../../../refs/TableRef'; -import { ColumnRef } from '../../../../refs/ColumnRef'; import { Join, Selection } from './types'; export interface AugmentedQuery { @@ -57,7 +57,7 @@ function collectJoins(query: AnyQuery, defaultSchema: string): Array { query, ).column(column), otherColumn: ColumnRef.fromRefOp(refOp, defaultSchema), - op: refOp.$ref.op ?? '=', + op: '=' as const, }, ]; }, diff --git a/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.test.ts b/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.test.ts index 90d14953..5c3cf200 100644 --- a/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.test.ts +++ b/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.test.ts @@ -1,7 +1,6 @@ +import { col } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { convertWhereToQueryProviderInput } from './convertWhereToQueryProviderInput'; -import { DB } from '../../../tests/generated'; -import { Table, col } from '@synthql/queries'; describe('convertWhereToQueryProviderInput', () => { const date = new Date(); @@ -35,10 +34,7 @@ describe('convertWhereToQueryProviderInput', () => { test.each(supportedCases)( 'convertWhereToQueryProviderInput(%o) should return %o', (where, expected) => { - const result = convertWhereToQueryProviderInput>( - 'actor', - where, - ); + const result = convertWhereToQueryProviderInput('actor', where); expect(result).toEqual(expected); }, @@ -65,10 +61,7 @@ describe('convertWhereToQueryProviderInput', () => { 'convertWhereToQueryProviderInput(%o) should throw an error', (where) => { expect(() => - convertWhereToQueryProviderInput>( - 'actor', - where, - ), + convertWhereToQueryProviderInput('actor', where), ).toThrow(); }, ); diff --git a/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.ts b/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.ts index 20b10b06..94e93047 100644 --- a/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.ts +++ b/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.ts @@ -1,13 +1,13 @@ -import { AnyQuery, Table, Where } from '@synthql/queries'; +import { AnyDB, AnyQuery, AnyTable, Query } from '@synthql/queries'; import { QueryProviderInput } from '../../../types/QueryProviderInput'; /** * Takes a `Where` object and converts it into a `QueryProviderInput` object. */ -export function convertWhereToQueryProviderInput>( - table: TTable, - where: Where, -): QueryProviderInput { +export function convertWhereToQueryProviderInput( + table: string, + where: Query['where'], +): QueryProviderInput { const qpi: Record = {}; for (const { op, column, value } of iterateQueryOperators({ @@ -58,7 +58,9 @@ function createUnsupportedQueryError(table: string, where: AnyQuery['where']) { * * This lets us iterate over the query operators in a query. */ -function* iterateQueryOperators(query: AnyQuery['where']): Generator< +function* iterateQueryOperators( + query: Pick, +): Generator< | { op: '='; column: string; diff --git a/packages/backend/src/query/iterateQuery.test.ts b/packages/backend/src/query/iterateQuery.test.ts index 52671534..465fbea9 100644 --- a/packages/backend/src/query/iterateQuery.test.ts +++ b/packages/backend/src/query/iterateQuery.test.ts @@ -1,8 +1,8 @@ -import { describe, expect, test } from 'vitest'; import { AnyQuery, col } from '@synthql/queries'; +import { describe, expect, test } from 'vitest'; +import { Path } from '../execution/types'; import { from } from '../tests/generated'; import { iterateQuery } from './iterateQuery'; -import { Path } from '../execution/types'; describe('iterateQuery', () => { const cases: Array<{ @@ -194,6 +194,7 @@ describe('iterateQuery', () => { where: { film_id: 1, }, + schema: {}, }, expected: [ { @@ -201,6 +202,7 @@ describe('iterateQuery', () => { from: 'film', select: {}, where: { film_id: 1 }, + schema: {}, }, insertionPath: [], }, diff --git a/packages/backend/src/tests/benchmarks/bench.test.ts b/packages/backend/src/tests/benchmarks/bench.test.ts index 196ffe3a..e79f05ed 100644 --- a/packages/backend/src/tests/benchmarks/bench.test.ts +++ b/packages/backend/src/tests/benchmarks/bench.test.ts @@ -1,11 +1,11 @@ import { col } from '@synthql/queries'; +import Benchmark from 'benchmark'; +import fs from 'fs'; +import path from 'path'; import { describe, test } from 'vitest'; import { collectLast } from '../..'; import { from } from '../generated'; import { queryEngine } from '../queryEngine'; -import Benchmark from 'benchmark'; -import fs from 'fs'; -import path from 'path'; describe('Benchmark tests', () => { test(`Find matching rows`, async () => { diff --git a/packages/backend/src/tests/compareStores.ts b/packages/backend/src/tests/compareStores.ts index dac20b6f..21b857e8 100644 --- a/packages/backend/src/tests/compareStores.ts +++ b/packages/backend/src/tests/compareStores.ts @@ -10,6 +10,5 @@ export const compareStores = ( a: SelectedStoreColumnDataTypes, b: SelectedStoreColumnDataTypes, ) => { - // Q: does this compare ascending or descending? return a.store_id - b.store_id; }; diff --git a/packages/backend/src/tests/e2e/nx1.test.ts b/packages/backend/src/tests/e2e/nx1.test.ts index c4fe355b..18c6fb42 100644 --- a/packages/backend/src/tests/e2e/nx1.test.ts +++ b/packages/backend/src/tests/e2e/nx1.test.ts @@ -28,7 +28,7 @@ describe('n x 1', () => { const q = findFilm({ film_id: 1 }); const queryResult = await collectLast( - execute(q, { + execute(q, { defaultSchema: 'public', executors: [ new QueryProviderExecutor([ diff --git a/packages/backend/src/tests/e2e/nxm.test.ts b/packages/backend/src/tests/e2e/nxm.test.ts index 8992cf79..851689d4 100644 --- a/packages/backend/src/tests/e2e/nxm.test.ts +++ b/packages/backend/src/tests/e2e/nxm.test.ts @@ -7,7 +7,7 @@ import { createExecutionPlan } from '../../execution/planning/createExecutionPla import { simplifyPlan } from '../../execution/planning/simplifyPlan'; import { describeQuery } from '../../query/describeQuery'; import { compareInventory } from '../compareInventory'; -import { DB, from } from '../generated'; +import { from } from '../generated'; import { sql } from '../postgres'; import { pool } from '../queryEngine'; @@ -92,7 +92,7 @@ describe('n x m', () => { LIMIT 1 `; - const result = await collectLast(execute(q, execProps)); + const result = await collectLast(execute(q, execProps)); const expected = rows[0]; expect(result.store_id).toEqual(expected.store_id); diff --git a/packages/backend/src/tests/e2e/payments.test.ts b/packages/backend/src/tests/e2e/payments.test.ts index f9412f9e..69498a9d 100644 --- a/packages/backend/src/tests/e2e/payments.test.ts +++ b/packages/backend/src/tests/e2e/payments.test.ts @@ -1,11 +1,11 @@ import { describe, expect, test } from 'vitest'; -import { DB, from } from '../generated'; -import { describeQuery } from '../../query/describeQuery'; -import { PgExecutor } from '../../execution/executors/PgExecutor'; -import { pool } from '../queryEngine'; -import { execute } from '../../execution/execute'; import { collectLast } from '../..'; +import { execute } from '../../execution/execute'; +import { PgExecutor } from '../../execution/executors/PgExecutor'; +import { describeQuery } from '../../query/describeQuery'; +import { from } from '../generated'; import { sql } from '../postgres'; +import { pool } from '../queryEngine'; describe('e2e', () => { const q = from('payment') @@ -26,7 +26,7 @@ describe('e2e', () => { executors: [pgExecutor], }; - const result = await collectLast(execute(q, execProps)); + const result = await collectLast(execute(q, execProps)); const expected = await sql` SELECT diff --git a/packages/backend/src/tests/e2e/store-with-customers.test.ts b/packages/backend/src/tests/e2e/store-with-customers.test.ts index 4e43d50a..b859894f 100644 --- a/packages/backend/src/tests/e2e/store-with-customers.test.ts +++ b/packages/backend/src/tests/e2e/store-with-customers.test.ts @@ -13,8 +13,8 @@ import { sortRecursively } from '../sortRecursively'; describe('e2e', () => { const payments = from('payment') - .groupBy('payment_id', 'payment_date') .columns('payment_id', 'amount') + .groupBy('payment_id', 'payment_date') .where({ customer_id: col('customer.customer_id') }) .many(); @@ -28,10 +28,10 @@ describe('e2e', () => { const q = store() .columns('store_id') + .where({ store_id: { in: [1] } }) .include({ customers, }) - .where({ store_id: { in: [1] } }) .one(); const pgExecutor = new PgExecutor({ @@ -71,12 +71,13 @@ describe('e2e', () => { GROUP BY s.store_id `; - const result = await collectLast(execute(q, execProps)); + const result = await collectLast(execute(q, execProps)); assertPresent(result); const expected = rows[0]; + // @ts-ignore (TODO(fhur)) expect(result.store_id).toEqual(expected.store_id); const sliceIndex = 1; diff --git a/packages/backend/src/tests/e2e/store-with-films.test.ts b/packages/backend/src/tests/e2e/store-with-films.test.ts index b89f9aaf..23274677 100644 --- a/packages/backend/src/tests/e2e/store-with-films.test.ts +++ b/packages/backend/src/tests/e2e/store-with-films.test.ts @@ -1,3 +1,4 @@ +import { QueryResult, col } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { collectLast } from '../..'; import { execute } from '../../execution/execute'; @@ -7,9 +8,8 @@ import { assertPresent } from '../../util/asserts/assertPresent'; import { compareInventory } from '../compareInventory'; import { DB } from '../generated'; import { sql } from '../postgres'; -import { inventory, store, film, filmActor, actor } from '../queries.v2'; +import { actor, film, filmActor, inventory, store } from '../queries.v2'; import { pool } from '../queryEngine'; -import { QueryResult, col } from '@synthql/queries'; describe('e2e', () => { const actors = filmActor() @@ -73,7 +73,7 @@ describe('e2e', () => { s.store_id `; - const result = await collectLast(execute(q, execProps)); + const result = await collectLast(execute(q, execProps)); assertPresent(result); const expected = rows[0]; expect(result.store_id).toEqual(expected.store_id); diff --git a/packages/backend/src/tests/propertyBased/arbitraries/ArbitraryQueryBuilder.ts b/packages/backend/src/tests/propertyBased/arbitraries/ArbitraryQueryBuilder.ts index cb1ba604..6390d87d 100644 --- a/packages/backend/src/tests/propertyBased/arbitraries/ArbitraryQueryBuilder.ts +++ b/packages/backend/src/tests/propertyBased/arbitraries/ArbitraryQueryBuilder.ts @@ -1,17 +1,10 @@ -import { - Cardinality, - Column, - Query, - Schema, - Select, - Table, - Where, -} from '@synthql/queries'; +import { Any } from '@sinclair/typebox'; +import { Cardinality, Column, Query, Schema, Table } from '@synthql/queries'; import fc from 'fast-check'; -import { schema, DB as PagilaDB } from '../../generated'; +import { DB as PagilaDB, schema } from '../../generated'; +import { getTableDef } from '../getTableDef'; import { getTableNames } from '../getTableNames'; import { getTableSelectableColumns } from '../getTableSelectableColumns'; -import { getTableDef } from '../getTableDef'; import { tablesToSkip } from '../tablesToSkip'; export class ArbitraryQueryBuilder { @@ -83,7 +76,7 @@ export class ArbitraryQueryBuilder { private arbSelect>( tableName: TTable, - ): fc.Arbitrary> { + ): fc.Arbitrary { return fc .subarray( getTableSelectableColumns(this.schema, tableName) as Column< @@ -102,13 +95,13 @@ export class ArbitraryQueryBuilder { select[col] = fc.constant(true); }); - return fc.record>(select); + return fc.record(select); }); } private arbWhere>( tableName: TTable, - ): fc.Arbitrary> { + ): fc.Arbitrary { if (this.hasResults) { // for now we will just return all rows return fc.constant({}); @@ -136,14 +129,15 @@ export class ArbitraryQueryBuilder { build() { const table = this.arbTable(); - return table.chain>((tableName) => { - return fc.record>>({ + return table.chain((tableName) => { + return fc.record({ from: fc.constant(tableName), select: this.arbSelect(tableName), cardinality: this.arbCardinality(), where: this.arbWhere(tableName), groupBy: this.arbGroupBy(tableName), limit: this.arbLimit(), + schema: fc.constant(Any()), }); }); } diff --git a/packages/backend/src/tests/propertyBased/arbitraries/arbitraryQuery.ts b/packages/backend/src/tests/propertyBased/arbitraries/arbitraryQuery.ts index 31935e7e..aed40edc 100644 --- a/packages/backend/src/tests/propertyBased/arbitraries/arbitraryQuery.ts +++ b/packages/backend/src/tests/propertyBased/arbitraries/arbitraryQuery.ts @@ -1,12 +1,13 @@ import { fc } from '@fast-check/vitest'; +import { Any } from '@sinclair/typebox'; import { AnyQuery, Cardinality, Schema } from '@synthql/queries'; -import { arbitraryLimit } from './arbitraryLimit'; -import { arbitraryCardinality } from './arbitraryCardinality'; -import { arbitraryWhere } from './arbitraryWhere'; -import { arbitrarySelect } from './arbitrarySelect'; -import { AllTablesRowsMap } from '../getTableRowsByTableName'; import { getTableNames } from '../getTableNames'; +import { AllTablesRowsMap } from '../getTableRowsByTableName'; import { tablesToSkip } from '../tablesToSkip'; +import { arbitraryCardinality } from './arbitraryCardinality'; +import { arbitraryLimit } from './arbitraryLimit'; +import { arbitrarySelect } from './arbitrarySelect'; +import { arbitraryWhere } from './arbitraryWhere'; interface ArbitraryQuery { schema: Schema; @@ -27,18 +28,20 @@ export function arbitraryQuery({ (table) => !tablesToSkip.includes(table), ), ) - .chain((tableName) => - fc.record({ - from: fc.constant(tableName), - select: arbitrarySelect({ schema, tableName }), - where: arbitraryWhere({ - schema, - allTablesRowsMap, - tableName, - validWhere, + .chain( + (tableName): fc.Arbitrary => + fc.record({ + from: fc.constant(tableName), + select: arbitrarySelect({ schema, tableName }), + where: arbitraryWhere({ + schema, + allTablesRowsMap, + tableName, + validWhere, + }), + limit: arbitraryLimit(), + cardinality: arbitraryCardinality(cardinality), + schema: fc.constant(Any()), }), - limit: arbitraryLimit(), - cardinality: arbitraryCardinality(cardinality), - }), ); } diff --git a/packages/backend/src/tests/propertyBased/arbitraries/arbitrarySelect.ts b/packages/backend/src/tests/propertyBased/arbitraries/arbitrarySelect.ts index d7e394d4..b4bf287d 100644 --- a/packages/backend/src/tests/propertyBased/arbitraries/arbitrarySelect.ts +++ b/packages/backend/src/tests/propertyBased/arbitraries/arbitrarySelect.ts @@ -1,5 +1,5 @@ import { fc } from '@fast-check/vitest'; -import { AnyDB, Schema, Select } from '@synthql/queries'; +import { Query, Schema } from '@synthql/queries'; import { getTableSelectableColumns } from '../getTableSelectableColumns'; export function arbitrarySelect({ @@ -8,7 +8,7 @@ export function arbitrarySelect({ }: { schema: Schema; tableName: string; -}): fc.Arbitrary> { +}): fc.Arbitrary { return fc .constantFrom(getTableSelectableColumns(schema, tableName)) .chain((keys) => diff --git a/packages/backend/src/tests/propertyBased/properties/cardinalityMany.test.ts b/packages/backend/src/tests/propertyBased/properties/cardinalityMany.test.ts index ecdd0166..49fa109b 100644 --- a/packages/backend/src/tests/propertyBased/properties/cardinalityMany.test.ts +++ b/packages/backend/src/tests/propertyBased/properties/cardinalityMany.test.ts @@ -1,6 +1,6 @@ import { it } from '@fast-check/vitest'; -import { describe, expect } from 'vitest'; import { Query } from '@synthql/queries'; +import { describe, expect } from 'vitest'; import { DB, schema } from '../../generated'; import { pool, queryEngine } from '../../queryEngine'; import { arbitraryQuery } from '../arbitraries/arbitraryQuery'; @@ -51,7 +51,7 @@ describe('cardinalityMany', async () => { it.skip.prop([invalidWhereArbitraryQuery], { verbose: 2 })( 'Invalid where query should return empty array', async (query) => { - const typedQuery = query as Query; + const typedQuery = query; const queryResult = await queryEngine.executeAndWait(typedQuery); diff --git a/packages/backend/src/tests/propertyBased/properties/cardinalityMaybe.test.ts b/packages/backend/src/tests/propertyBased/properties/cardinalityMaybe.test.ts index ac59bcc2..de1be957 100644 --- a/packages/backend/src/tests/propertyBased/properties/cardinalityMaybe.test.ts +++ b/packages/backend/src/tests/propertyBased/properties/cardinalityMaybe.test.ts @@ -1,6 +1,6 @@ import { it } from '@fast-check/vitest'; -import { describe, expect } from 'vitest'; import { Query } from '@synthql/queries'; +import { describe, expect } from 'vitest'; import { DB, schema } from '../../generated'; import { pool, queryEngine } from '../../queryEngine'; import { arbitraryQuery } from '../arbitraries/arbitraryQuery'; @@ -24,7 +24,7 @@ describe('cardinalityMaybe', async () => { it.prop([validWhereArbitraryQuery], { verbose: 2 })( 'Valid where query should return a possibly null, non-array, TS object result', async (query) => { - const typedQuery = query as Query; + const typedQuery = query; const queryResult = await queryEngine.executeAndWait(typedQuery); diff --git a/packages/backend/src/tests/propertyBased/properties/cardinalityOne.test.ts b/packages/backend/src/tests/propertyBased/properties/cardinalityOne.test.ts index 867a8160..ec282f43 100644 --- a/packages/backend/src/tests/propertyBased/properties/cardinalityOne.test.ts +++ b/packages/backend/src/tests/propertyBased/properties/cardinalityOne.test.ts @@ -1,11 +1,10 @@ import { it } from '@fast-check/vitest'; import { describe, expect } from 'vitest'; -import { Query } from '@synthql/queries'; +import { SynthqlError } from '../../../SynthqlError'; import { DB, schema } from '../../generated'; import { pool, queryEngine } from '../../queryEngine'; import { arbitraryQuery } from '../arbitraries/arbitraryQuery'; import { getTableRowsByTableName } from '../getTableRowsByTableName'; -import { SynthqlError } from '../../../SynthqlError'; describe('cardinalityOne', async () => { const validWhereArbitraryQuery = arbitraryQuery({ @@ -25,7 +24,7 @@ describe('cardinalityOne', async () => { it.prop([validWhereArbitraryQuery], { verbose: 2 })( 'Valid where query should return a non-null, non-array, TS object result', async (query) => { - const typedQuery = query as Query; + const typedQuery = query; const queryResult = await queryEngine.executeAndWait(typedQuery); @@ -53,7 +52,7 @@ describe('cardinalityOne', async () => { 'Invalid where query should throw expected cardinality error', async (query) => { try { - const typedQuery = query as Query; + const typedQuery = query; await queryEngine.executeAndWait(typedQuery); } catch (error) { expect(error).toBeInstanceOf(SynthqlError); diff --git a/packages/backend/src/tests/queries.v2.ts b/packages/backend/src/tests/queries.v2.ts index 829041cc..65cf99ac 100644 --- a/packages/backend/src/tests/queries.v2.ts +++ b/packages/backend/src/tests/queries.v2.ts @@ -10,7 +10,7 @@ export function actor() { } export function filmActor() { - return from('film_actor').groupBy('actor_id', 'film_id').columns(); + return from('film_actor').columns().groupBy('actor_id', 'film_id'); } export function film() { diff --git a/packages/cli/package.json b/packages/cli/package.json index 591680ab..2ed43fbe 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -24,7 +24,7 @@ "checks": "yarn vitest --globals run && yarn build && yarn tsc", "build": "vite build --mode production", "publish:minor": "yarn publish --access public --no-git-tag-version", - "format": "yarn prettier --config ../../prettier.config.js --write ./src/" + "format": "yarn prettier --config ../../.prettierrc.js --write ./src/" }, "dependencies": { "@synthql/introspect": "0.95.4", diff --git a/packages/cli/src/e2e.test.ts b/packages/cli/src/e2e.test.ts index ad0f5aa8..37f7156c 100644 --- a/packages/cli/src/e2e.test.ts +++ b/packages/cli/src/e2e.test.ts @@ -1,8 +1,8 @@ -import { afterAll, beforeAll, describe, expect, test } from 'vitest'; -import * as prettier from 'prettier'; +import { randomUUID } from 'crypto'; import fs from 'fs'; import path from 'path'; -import { randomUUID } from 'crypto'; +import * as prettier from 'prettier'; +import { afterAll, beforeAll, describe, expect, test } from 'vitest'; import { cli } from './cli'; import { configFileSchema } from './validators/schemas'; import { validateSchemaDefOverrides } from './validators/validators'; @@ -20,7 +20,7 @@ describe('e2e', () => { test('Write configuration file validation schema to files', async () => { const prettierOptions = await prettier.resolveConfig( - '../../.prettier.config.js', + '../../..prettierrc.js', ); expect(prettierOptions).not.toBe(null); diff --git a/packages/cli/vite.config.ts.timestamp-1727430152478-724472fcd03ee.mjs b/packages/cli/vite.config.ts.timestamp-1727430152478-724472fcd03ee.mjs new file mode 100644 index 00000000..e69de29b diff --git a/packages/docs/package.json b/packages/docs/package.json index 9e81f266..24dc2cf6 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -14,7 +14,7 @@ "write-translations": "docusaurus write-translations", "write-heading-ids": "docusaurus write-heading-ids", "typecheck": "tsc", - "format": "yarn prettier --config ../../prettier.config.js --write ./src/" + "format": "yarn prettier --config ../../.prettierrc.js --write ./src/" }, "dependencies": { "@docusaurus/core": "3.1.0", diff --git a/packages/handler-express/package.json b/packages/handler-express/package.json index 55d2a0c9..4a72acaf 100644 --- a/packages/handler-express/package.json +++ b/packages/handler-express/package.json @@ -24,7 +24,7 @@ "typecheck": "tsc", "checks": "yarn vitest run && yarn tsc", "publish:minor": "yarn publish --access public --no-git-tag-version", - "format": "yarn prettier --config ../../prettier.config.js --write ./src/" + "format": "yarn prettier --config ../../.prettierrc.js --write ./src/" }, "dependencies": { "@synthql/backend": "0.95.4", diff --git a/packages/handler-next/package.json b/packages/handler-next/package.json index 6963c9dd..20650e9c 100644 --- a/packages/handler-next/package.json +++ b/packages/handler-next/package.json @@ -24,7 +24,7 @@ "typecheck": "tsc", "checks": "yarn vitest run && yarn tsc", "publish:minor": "yarn publish --access public --no-git-tag-version", - "format": "yarn prettier --config ../../prettier.config.js --write ./src/" + "format": "yarn prettier --config ../../.prettierrc.js --write ./src/" }, "dependencies": { "@synthql/backend": "0.95.4", diff --git a/packages/introspect/package.json b/packages/introspect/package.json index ff45ff38..164c9d59 100644 --- a/packages/introspect/package.json +++ b/packages/introspect/package.json @@ -27,7 +27,7 @@ "checks": "yarn vitest --globals run && yarn build && yarn tsc", "build": "vite build --mode production", "publish:minor": "yarn publish --access public --no-git-tag-version", - "format": "yarn prettier --config ../../prettier.config.js --write ./src/" + "format": "yarn prettier --config ../../.prettierrc.js --write ./src/" }, "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.5.4", diff --git a/packages/introspect/src/e2e.test.ts b/packages/introspect/src/e2e.test.ts index 6a13ff60..78f32ebe 100644 --- a/packages/introspect/src/e2e.test.ts +++ b/packages/introspect/src/e2e.test.ts @@ -1,11 +1,11 @@ +import * as prettier from 'prettier'; import { describe, expect, test } from 'vitest'; import { generate } from './generate'; -import * as prettier from 'prettier'; describe('e2e', () => { test('Generate from Pagila', async () => { const prettierOptions = await prettier.resolveConfig( - '../../.prettier.config.js', + '../../..prettierrc.js', ); expect(prettierOptions).not.toBe(null); diff --git a/packages/queries/package.json b/packages/queries/package.json index 442bcd69..07a5639d 100644 --- a/packages/queries/package.json +++ b/packages/queries/package.json @@ -26,10 +26,13 @@ "test:ci": "CI=1 vitest run --globals", "checks": "yarn vitest --globals run && yarn build && yarn tsc", "build": "vite build --mode production", + "build:watch": "nodemon -x \"yarn typecheck && yarn build\" -e \"ts\" -w \"packages/**/*\"", "publish:minor": "yarn publish --access public --no-git-tag-version", - "format": "yarn prettier --config ../../prettier.config.js --write ./src/" + "format": "yarn prettier --config ../../.prettierrc.js --write ./src/" + }, + "dependencies": { + "@sinclair/typebox": "^0.33.12" }, - "dependencies": {}, "devDependencies": { "rollup-plugin-node-externals": "^7.1.1", "typescript": "^5.4.5", diff --git a/packages/queries/src/QueryBuilderError.ts b/packages/queries/src/QueryBuilderError.ts index f9a14ea9..f6544008 100644 --- a/packages/queries/src/QueryBuilderError.ts +++ b/packages/queries/src/QueryBuilderError.ts @@ -2,11 +2,11 @@ import { AnyQuery } from './types/AnyQuery'; export class QueryBuilderError extends Error { constructor( - public query: AnyQuery, public type: string, public message: string, ) { super(message); + this.type = type; Error.captureStackTrace(this, QueryBuilderError); } @@ -14,8 +14,8 @@ export class QueryBuilderError extends Error { query, nestedQuery, }: { - query: AnyQuery; - nestedQuery: AnyQuery; + query: { from: string }; + nestedQuery: { from: string }; }): QueryBuilderError { const type = 'NestedQueryMissingRefOpWhereClauseError'; @@ -28,6 +28,6 @@ export class QueryBuilderError extends Error { ``, ]; - return new QueryBuilderError(query, type, lines.join('\n')); + return new QueryBuilderError(type, lines.join('\n')); } } diff --git a/packages/queries/src/col.ts b/packages/queries/src/col.ts index 78b01403..c6882d97 100644 --- a/packages/queries/src/col.ts +++ b/packages/queries/src/col.ts @@ -1,5 +1,5 @@ -import { RefOp } from './types/RefOp'; import { ColumnReference } from './types/ColumnReference'; +import { RefOp } from './types/RefOp'; export function col(ref: ColumnReference): RefOp { const parts = ref.split('.'); @@ -8,7 +8,6 @@ export function col(ref: ColumnReference): RefOp { $ref: { table: parts[0] as any, column: parts[1] as any, - op: '=', }, }; } @@ -17,7 +16,6 @@ export function col(ref: ColumnReference): RefOp { $ref: { table: `${parts[0]}.${parts[1]}` as any, column: parts[2] as any, - op: '=', }, }; } diff --git a/packages/queries/src/index.ts b/packages/queries/src/index.ts index 2581be8d..0d61b364 100644 --- a/packages/queries/src/index.ts +++ b/packages/queries/src/index.ts @@ -4,7 +4,6 @@ export * from './types/BinaryOp'; export * from './types/Cardinality'; export * from './types/Column'; export * from './types/ColumnValue'; -export * from './types/Include'; export * from './types/JoinOp'; export * from './types/QueryParameter'; export * from './types/QueryResult'; diff --git a/packages/queries/src/query.test.ts b/packages/queries/src/query.test.ts index 882b9b98..3e4dc89e 100644 --- a/packages/queries/src/query.test.ts +++ b/packages/queries/src/query.test.ts @@ -1,20 +1,28 @@ import { describe, test } from 'vitest'; -import { Query, QueryResult, Table, col } from '.'; +import { AnyQuery, Query, QueryResult, col } from '.'; import { DB, from } from './generated'; describe('queries', () => { - function fakeQueryResult>>( - q: TQuery, - ): QueryResult { + function fakeQueryResult(q: T): QueryResult { return {} as any; } + function testAssignableToAnyQuery(q: AnyQuery) { + // Do nothing + } + + function testAssignableToQuery(q: Query): Query { + return q; + } + test('Find one actor with `name()`', () => { const q = from('actor') .columns('actor_id', 'first_name') .name('findActor') .one(); + testAssignableToAnyQuery(q); + testAssignableToQuery(q); const result = fakeQueryResult(q); result satisfies { actor_id: number; first_name: string }; @@ -23,19 +31,18 @@ describe('queries', () => { test('Find one actor with `columns()`', () => { const q = from('actor').columns('actor_id', 'first_name').one(); + testAssignableToAnyQuery(q); + testAssignableToQuery(q); const result = fakeQueryResult(q); result satisfies { actor_id: number; first_name: string }; }); test('Find one actor with `select()`', () => { - const q = from('actor') - .select({ - actor_id: true, - first_name: true, - }) - .one(); + const q = from('actor').columns('actor_id', 'first_name').one(); + testAssignableToAnyQuery(q); + testAssignableToQuery(q); const result = fakeQueryResult(q); result satisfies { actor_id: number; first_name: string }; @@ -44,6 +51,8 @@ describe('queries', () => { test('Find one actor with automatic select of all selectable columns', () => { const q = from('actor').one(); + testAssignableToAnyQuery(q); + testAssignableToQuery(q); const result = fakeQueryResult(q); result satisfies { @@ -57,6 +66,8 @@ describe('queries', () => { test('Find many actors', () => { const q = from('actor').columns('actor_id', 'first_name').many(); + testAssignableToAnyQuery(q); + testAssignableToQuery(q); const result = fakeQueryResult(q); result satisfies Array<{ actor_id: number; first_name: string }>; }); @@ -67,6 +78,8 @@ describe('queries', () => { .offset(2) .many(); + testAssignableToAnyQuery(q); + testAssignableToQuery(q); const result = fakeQueryResult(q); result satisfies Array<{ actor_id: number; first_name: string }>; }); @@ -105,18 +118,19 @@ describe('queries', () => { test('Find film with language and actors', () => { const language = from('language') - .columns('language_id', 'name') .where({ language_id: col('film.language_id') }) + .columns('language_id', 'name') .maybe(); const filmActor = from('film_actor') - .select({}) .where({ film_id: col('film.film_id') }) + .columns() .many(); const actors = from('actor') - .columns('actor_id', 'first_name', 'last_name') + .offset(10) .where({ actor_id: col('film_actor.actor_id') }) + .columns('actor_id', 'first_name', 'last_name') .many(); const q = from('film') @@ -128,6 +142,9 @@ describe('queries', () => { }) .one(); + testAssignableToQuery(q).schema; + testAssignableToAnyQuery(q); + const result = fakeQueryResult(q); result satisfies { @@ -144,4 +161,37 @@ describe('queries', () => { }>; }; }); + + test('', () => { + const address = from('address').columns('address_id', 'city_id').one(); + const staff = from('staff') + .columns('staff_id') + .where({ + address_id: col('address.address_id'), + }) + .one(); + + const store = from('store') + .columns('store_id', 'address_id') + .columns('address_id') + .include({ + address, + }) + .include({ + address: from('address').columns('address2').one(), + }) + .include({ + staff, + }) + .all(); + + const result = fakeQueryResult(store); + result satisfies Array<{ + address_id: number; + address: { + address_id: number; + city_id: number; + }; + }>; + }); }); diff --git a/packages/queries/src/query.ts b/packages/queries/src/query.ts index c561cf58..138a8a4c 100644 --- a/packages/queries/src/query.ts +++ b/packages/queries/src/query.ts @@ -1,118 +1,62 @@ -import { Table } from './types/Table'; +import { + Static, + Type as t, + TArray, + TObject, + TPick, + TSchema, +} from '@sinclair/typebox'; +import { Assert } from '@sinclair/typebox/value'; +import { getTablePrimaryKeyColumns } from './schema/getTablePrimaryKeyColumns'; +import { getTableSchema } from './schema/getTableSchema'; +import { getTableSelectableColumns } from './schema/getTableSelectableColumns'; import { Column } from './types/Column'; +import { ColumnValue } from './types/ColumnValue'; +import { Schema } from './types/Schema'; import { Select } from './types/Select'; +import { Table } from './types/Table'; +import { Query, QuerySchema } from './types/types'; import { Where } from './types/Where'; -import { Include } from './types/Include'; -import { Cardinality } from './types/Cardinality'; -import { Schema } from './types/Schema'; -import { getTableSelectableColumns } from './schema/getTableSelectableColumns'; -import { getTablePrimaryKeyColumns } from './schema/getTablePrimaryKeyColumns'; -import { validateNestedQueriesHaveAValidRefOp } from './validators/validateNestedQueriesHaveAValidRefOp'; import { hashQuery } from './util/hashQuery'; +import { validateNestedQueriesHaveAValidRefOp } from './validators/validateNestedQueriesHaveAValidRefOp'; export class QueryBuilder< DB, TTable extends Table, - TWhere extends Where, - TSelect extends Select, - TInclude extends Include, - TLimit extends number | undefined, - TOffset extends number | undefined, - TCardinality extends Cardinality, - TLazy extends true | undefined, - TGroupBy extends string[], + TResultSchema extends TSchema, > { constructor( - private _from: TTable, - private _where: TWhere, - private _select: TSelect, - private _include: TInclude, - private _limit: TLimit, - private _offset: TOffset, - private _cardinality: TCardinality, - private _lazy: TLazy, - private _groupBy: TGroupBy, - private _name?: string, - ) { - validateNestedQueriesHaveAValidRefOp({ - from: this._from, - where: this._where, - select: this._select, - include: this._include, - limit: this._limit, - offset: this._offset, - cardinality: this._cardinality ?? 'many', - lazy: this._lazy, - groupBy: this._groupBy, - name: this._name, - }); - } + private query: Partial, + private schema: TResultSchema, + ) {} + + private build(): Query { + const built: Query = assertQuery( + this.query, + this.schema, + ); + + built.hash = hashQuery(built); + + const whereColumns = + Object.keys(built.where).slice(0, 2).join('-and-') || 'all'; + built.name = built.name ?? `${built.from}-by-${whereColumns}`; - private build(): { - from: TTable; - where: TWhere; - select: TSelect; - include: TInclude; - limit: TLimit; - offset: TOffset; - cardinality: TCardinality; - lazy: TLazy; - groupBy: TGroupBy; - hash: string; - name?: string; - } { - return { - from: this._from, - where: this._where, - select: this._select, - include: this._include, - limit: this._limit, - offset: this._offset, - cardinality: this._cardinality ?? 'many', - lazy: this._lazy, - groupBy: this._groupBy, - hash: hashQuery({ - from: this._from, - where: this._where, - select: this._select, - include: this._include, - limit: this._limit, - offset: this._offset, - cardinality: this._cardinality ?? 'many', - lazy: this._lazy, - groupBy: this._groupBy, - name: this._name, - }), - name: this._name, - }; + validateNestedQueriesHaveAValidRefOp(built); + return built; } /** * Sets the limit of the query. */ - limit(limit: TLimit) { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - TLimit, - TOffset, - TCardinality, - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - this._include, - limit, - this._offset, - this._cardinality, - this._lazy, - this._groupBy, - this._name, + limit(limit: number) { + const query = this.query; + return new QueryBuilder( + { + ...query, + limit, + }, + this.schema, ); } @@ -156,58 +100,28 @@ export class QueryBuilder< * for the query, and then builds the query. * Shorthand for `.limit(n).all()`. */ - take(take: TLimit) { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - TLimit, - TOffset, - 'many', - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - this._include, - take, - this._offset, - 'many', - this._lazy, - this._groupBy, - this._name, - ).build(); + take(take: number) { + const query = this.query; + return new QueryBuilder( + { + ...query, + limit: take, + }, + this.schema, + ).all(); } /** * Sets the number (n) of rows to skip before returning results. */ - offset(offset: TOffset) { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - TLimit, - TOffset, - TCardinality, - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - this._include, - this._limit, - offset, - this._cardinality, - this._lazy, - this._groupBy, - this._name, + offset(offset: number): QueryBuilder { + const query = this.query; + return new QueryBuilder( + { + ...query, + offset, + }, + this.schema, ); } @@ -215,57 +129,30 @@ export class QueryBuilder< * @alias {@link firstOrThrow} */ one() { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - 1, - TOffset, - 'one', - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - this._include, - 1, - this._offset, - 'one', - this._lazy, - this._groupBy, - this._name, + const query = this.query; + return new QueryBuilder( + { + ...query, + limit: 1, + cardinality: 'one', + }, + this.schema, ).build(); } /** * @alias {@link all} */ - many() { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - TLimit, - TOffset, - 'many', - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - this._include, - this._limit, - this._offset, - 'many', - this._lazy, - this._groupBy, - this._name, + many(): Query> { + const query = this.query; + const schema = t.Array(this.schema); + + return new QueryBuilder( + { + ...query, + cardinality: 'many', + }, + t.Array(this.schema), ).build(); } @@ -273,55 +160,20 @@ export class QueryBuilder< * @alias {@link first} */ maybe() { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - 1, - TOffset, - 'maybe', - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - this._include, - 1, - this._offset, - 'maybe', - this._lazy, - this._groupBy, - this._name, + const query = this.query; + return new QueryBuilder( + { + ...query, + limit: 1, + cardinality: 'maybe', + }, + this.schema, ).build(); } select>(select: TSelect) { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - TLimit, - TOffset, - TCardinality, - TLazy, - TGroupBy - >( - this._from, - this._where, - select, - this._include, - this._limit, - this._offset, - this._cardinality, - this._lazy, - this._groupBy, - this._name, - ); + const columns = Object.keys(select) as Column[]; + return this.columns(...columns); } /** @@ -343,172 +195,97 @@ export class QueryBuilder< * }); * ``` */ - columns>>(...keys: TKeys) { + columns>>( + ...keys: TKeys + ): QueryBuilder> { type SelectFromKeys = { [k in TKeys[number]]: true }; const select = keys.reduce((acc, key) => { return { ...acc, [key]: true }; }, {} as SelectFromKeys); - return new QueryBuilder< - DB, - TTable, - TWhere, - { [k in TKeys[number]]: true }, - TInclude, - TLimit, - TOffset, - TCardinality, - TLazy, - TGroupBy - >( - this._from, - this._where, - select, - this._include, - this._limit, - this._offset, - this._cardinality, - this._lazy, - this._groupBy, - this._name, + return new QueryBuilder( + { + ...this.query, + select, + }, + t.Pick(this.schema, keys) as unknown as TPick, ); } - include>(include: TInclude) { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - TLimit, - TOffset, - TCardinality, - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - include, - this._limit, - this._offset, - this._cardinality, - this._lazy, - this._groupBy, - this._name, - ); - } + include>( + include: TInclude, + ): QueryBuilder> { + const query = this.query; + + const schema = t.Composite([ + this.schema, + t.Object( + Object.entries(include) + .map(([key, value]) => { + return { [key]: value.schema }; + }) + .reduce((acc, curr) => ({ ...acc, ...curr }), {}) as any, + ), + ]) as unknown as AppendToSchema; - alsoInclude>(include: TNewInclude) { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude & TNewInclude, - TLimit, - TOffset, - TCardinality, - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - { ...this._include, ...include }, - this._limit, - this._offset, - this._cardinality, - this._lazy, - this._groupBy, - this._name, + return new QueryBuilder( + { + ...query, + include, + }, + schema, ); } - where(where: Where) { + where(where: Where): QueryBuilder { return this.filter(where); } - filter(where: Where) { - return new QueryBuilder< - DB, - TTable, - // Note that we don't merge the literal types, we are fine - // with the low resultion Where type, as the Where doesn't - // impact the QueryResult. - Where, - TSelect, - TInclude, - TLimit, - TOffset, - TCardinality, - TLazy, - TGroupBy - >( - this._from, - where, - this._select, - this._include, - this._limit, - this._offset, - this._cardinality, - this._lazy, - this._groupBy, - this._name, + filter(where: Where): QueryBuilder { + const query = this.query; + return new QueryBuilder( + { + ...query, + // TODO(fhur): fix this type assertion + where: where as any, + }, + this.schema, ); } + /** + * @deprecated use {@link defer} instead. + */ lazy() { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - TLimit, - TOffset, - TCardinality, - true, - TGroupBy - >( - this._from, - this._where, - this._select, - this._include, - this._limit, - this._offset, - this._cardinality, - true, - this._groupBy, - this._name, + return this.defer(); + } + + /** + * Splits the query into two queries. The first query is executed immediately, + * and the second query is executed once the first query is finished. + * + * Merging of the queries will happen inside the `QueryEngine`. + */ + defer() { + const query = this.query; + return new QueryBuilder( + { + ...query, + lazy: true, + }, + this.schema, ); } - groupBy[]>(...id: TGroupBy) { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - TLimit, - TOffset, - TCardinality, - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - this._include, - this._limit, - this._offset, - this._cardinality, - this._lazy, - id, - this._name, + groupBy[]>(...groupBy: TGroupBy) { + const query = this.query; + return new QueryBuilder( + { + ...query, + groupBy, + }, + this.schema, ); } @@ -525,28 +302,13 @@ export class QueryBuilder< * ``` */ name(name: string) { - return new QueryBuilder< - DB, - TTable, - TWhere, - TSelect, - TInclude, - TLimit, - TOffset, - TCardinality, - TLazy, - TGroupBy - >( - this._from, - this._where, - this._select, - this._include, - this._limit, - this._offset, - this._cardinality, - this._lazy, - this._groupBy, - name, + const query = this.query; + return new QueryBuilder( + { + ...query, + name, + }, + this.schema, ); } } @@ -554,35 +316,56 @@ export class QueryBuilder< export function query(schema: Schema) { return { from>(table: TTable) { - type TKeys = Array>; - const select = getTableSelectableColumns(schema, table); const primaryKeys = getTablePrimaryKeyColumns(schema, table); - return new QueryBuilder< - DB, - TTable, - {}, - { [k in TKeys[number]]: true }, - {}, - number | undefined, - number | undefined, - 'many', - undefined, - typeof primaryKeys - >( - table, - {}, - select, - {}, - undefined, - undefined, - 'many', - undefined, - primaryKeys, - undefined, + const tableSchema = getTableSchema(schema, table); + + type SelectAllSchema> = TObject<{ + [TColumn in Column]: TSchema & { + static: ColumnValue; + }; + }>; + + return new QueryBuilder>( + { + cardinality: 'many', + from: table, + groupBy: primaryKeys, + select, + where: {}, + }, + tableSchema as SelectAllSchema, ); }, }; } + +function assertQuery( + partialQuery: Partial, + schema: T, +): Query { + Assert(QuerySchema, partialQuery); + + return { ...partialQuery, schema }; +} + +type SchemaOf = TSchema & { static: StaticType }; + +type Append = (A & B) & {}; + +type AppendToSchema = SchemaOf< + Append< + Static, + { + [key in keyof TInclude]: TInclude[key] extends Query< + any, + any, + infer T + > + ? Static + : unknown; + } + > +>; diff --git a/packages/queries/src/schema/getTableSchema.ts b/packages/queries/src/schema/getTableSchema.ts new file mode 100644 index 00000000..fcf33ef9 --- /dev/null +++ b/packages/queries/src/schema/getTableSchema.ts @@ -0,0 +1,56 @@ +import { TSchema, TUnsafe, Type } from '@sinclair/typebox'; +import { Schema } from '../types/Schema'; +import { Select } from '../types/Select'; +import { Table } from '../types/Table'; +import { getColumnNamesAndDefs } from './getColumnNamesAndDefs'; +import { getTableDef } from './getTableDef'; +import { isSelectableColumn } from './isSelectableColumn'; + +export function getTableSchema>( + schema: Schema, + table: TTable, +): TUnsafe> { + const tableDef = getTableDef(schema, table); + + const columns = getColumnNamesAndDefs(tableDef) + // Only include selectable columns + .filter(([_, columnDef]) => { + return isSelectableColumn(columnDef); + }) + .map(([columnName, columnDef]) => { + return { + [columnName]: convertToTypeBoxSchema(columnDef.properties.type), + }; + }) + .reduce((acc, curr) => { + return { ...acc, ...curr }; + }, {}); + + return Type.Object(columns); +} + +function convertToTypeBoxSchema(jsonSchema: any): TSchema { + switch (jsonSchema.type) { + case 'string': + return Type.String(jsonSchema); + case 'number': + return Type.Number(jsonSchema); + case 'integer': + return Type.Integer(jsonSchema); + case 'boolean': + return Type.Boolean(jsonSchema); + case 'object': + const properties = {}; + for (const key in jsonSchema.properties) { + // @ts-ignore + properties[key] = convertToTypeBoxSchema( + jsonSchema.properties[key], + ); + } + return Type.Object(properties); + case 'array': + return Type.Array(convertToTypeBoxSchema(jsonSchema.items)); + default: + throw new Error('Unsupported JSON Schema type'); + } +} diff --git a/packages/queries/src/schema/getTableSelectableColumns.ts b/packages/queries/src/schema/getTableSelectableColumns.ts index 6e3d310e..5f370c7e 100644 --- a/packages/queries/src/schema/getTableSelectableColumns.ts +++ b/packages/queries/src/schema/getTableSelectableColumns.ts @@ -3,8 +3,6 @@ import { getColumnNamesAndDefs } from './getColumnNamesAndDefs'; import { getTableDef } from './getTableDef'; import { isSelectableColumn } from './isSelectableColumn'; -type SelectableColumnsRecordType = Record; - /** * Get the selectable columns of a table, as defined in the database schema. * @@ -28,8 +26,8 @@ type SelectableColumnsRecordType = Record; export function getTableSelectableColumns( schema: Schema, table: string, -): SelectableColumnsRecordType { - const select: SelectableColumnsRecordType = {}; +): Record { + const select: Record = {}; const tableDef = getTableDef(schema, table); diff --git a/packages/queries/src/types/AnyQuery.ts b/packages/queries/src/types/AnyQuery.ts index ae4de94d..afce5449 100644 --- a/packages/queries/src/types/AnyQuery.ts +++ b/packages/queries/src/types/AnyQuery.ts @@ -1,4 +1,3 @@ -import { Table } from './Table'; import { Query } from './types'; export type AnyTableDef = { @@ -15,5 +14,5 @@ export type AnyTableDef = { >; }; export type AnyDB = Record; -export type AnyTable = Table; -export type AnyQuery = Query; +export type AnyTable = string; +export type AnyQuery = Query; diff --git a/packages/queries/src/types/BinaryOp.ts b/packages/queries/src/types/BinaryOp.ts index 0f0918f8..00acb84a 100644 --- a/packages/queries/src/types/BinaryOp.ts +++ b/packages/queries/src/types/BinaryOp.ts @@ -1,7 +1,8 @@ -import { Table } from './Table'; +import { Type as t } from '@sinclair/typebox'; import { Column } from './Column'; -import { ColumnValue } from './ColumnValue'; -import { RefOp } from './RefOp'; +import { ColumnValue, ColumnValueSchema } from './ColumnValue'; +import { RefOp, RefOpSchema } from './RefOp'; +import { Table } from './Table'; export const BINARY_OPERATORS = [ '=', @@ -58,6 +59,11 @@ export const BINARY_OPERATORS = [ */ export type BinaryOperator = (typeof BINARY_OPERATORS)[number]; +export const BinaryOpSchema = t.Union([ + t.Record(t.Literal('='), RefOpSchema), + t.Record(t.String(), ColumnValueSchema), +]); + /** * A typed binary operator, which can be used in a `Where` clause. * diff --git a/packages/queries/src/types/Cardinality.ts b/packages/queries/src/types/Cardinality.ts index 7d71f8b9..5ffa6140 100644 --- a/packages/queries/src/types/Cardinality.ts +++ b/packages/queries/src/types/Cardinality.ts @@ -1,4 +1,12 @@ +import { Static, Type as t } from '@sinclair/typebox'; + +export const CardinalitySchema = t.Union([ + t.Literal('one'), + t.Literal('many'), + t.Literal('maybe'), +]); + /** * The cardinality of a query. */ -export type Cardinality = 'one' | 'maybe' | 'many'; +export type Cardinality = Static; diff --git a/packages/queries/src/types/ColumnValue.ts b/packages/queries/src/types/ColumnValue.ts index 926d66ef..1c7d5aab 100644 --- a/packages/queries/src/types/ColumnValue.ts +++ b/packages/queries/src/types/ColumnValue.ts @@ -1,5 +1,21 @@ -import { Table } from './Table'; +import { Type as t } from '@sinclair/typebox'; import { Column } from './Column'; +import { Table } from './Table'; + +const PrimitiveSchema = t.Union([ + t.String(), + t.Number(), + t.Boolean(), + t.Null(), + t.Undefined(), + t.BigInt(), + t.Date(), +]); + +export const ColumnValueSchema = t.Union([ + PrimitiveSchema, + t.Array(PrimitiveSchema), +]); /** * Get the data type of a column in the database. diff --git a/packages/queries/src/types/Include.ts b/packages/queries/src/types/Include.ts deleted file mode 100644 index 06d243f5..00000000 --- a/packages/queries/src/types/Include.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Table } from './Table'; -import { Query } from './types'; - -export type Include = { - [k in string]: Query> extends Query - ? Query - : never; -}; diff --git a/packages/queries/src/types/QueryResult.ts b/packages/queries/src/types/QueryResult.ts index 984a02d6..a2b30404 100644 --- a/packages/queries/src/types/QueryResult.ts +++ b/packages/queries/src/types/QueryResult.ts @@ -1,106 +1,9 @@ +import { Static } from '@sinclair/typebox'; import { Query } from './types'; -import { ColumnValue } from './ColumnValue'; -import { Column } from './Column'; -import { Table } from './Table'; -export type QueryResult = Simplify< - TQuery extends Query - ? ApplyCardinality - : never ->; +export type QueryResult = + TQuery extends Query + ? Simplify> + : unknown; -type Simplify = - T extends Array - ? Simplify[] - : T extends Date - ? T - : T extends object - ? { [K in keyof T]: Simplify } - : T; - -type QueryResultInner< - DB, - TTable extends Table, - TQuery extends Query, -> = QueryResultFromSelect & - QueryResultFromInclude; - -type QueryResultFromSelect< - DB, - TTable extends Table, - TQuery extends Query, -> = { - [TCol in SelectedColumns]: ColumnValue< - DB, - TTable, - TCol - >; -}; - -type SelectedColumns< - DB, - TTable extends Table, - TQuery extends Query, -> = TQuery['select'] extends true - ? // Select all columns - Column - : // Select only the specified columns - Column & keyof TQuery['select']; - -type IncludedColumns< - DB, - TTable extends Table, - TQuery extends Query, -> = keyof TQuery['include']; - -type QueryResultFromInclude< - DB, - TTable extends Table, - TQuery extends Query, -> = { - [TCol in IncludedColumns]: QueryResult< - DB, - TQuery['include'][TCol] - >; -}; - -type LazyQueryResult< - DB, - TTable extends Table, - TQuery extends Query, -> = - | { status: 'pending' } - | { status: 'done'; data: QueryResult } - | { status: 'error'; error: any }; - -type MaybeQueryResult< - DB, - TTable extends Table, - TQuery extends Query, -> = null | QueryResultInner; - -type ManyQueryResult< - DB, - TTable extends Table, - TQuery extends Query, -> = QueryResultInner[]; - -type ApplyCardinality< - DB, - TTable extends Table, - TQuery extends Query, -> = - // Case 1: lazy query - TQuery extends { lazy: true } - ? LazyQueryResult - : // Case 2: many - TQuery extends { cardinality: 'many' } - ? ManyQueryResult - : // Case 2: one - TQuery extends { cardinality: 'one' } - ? QueryResultInner - : // Case 2: maybe - TQuery extends { cardinality: 'maybe' } - ? MaybeQueryResult - : // Else - never; +type Simplify = T extends object ? { [K in keyof T]: Simplify } : T; diff --git a/packages/queries/src/types/RefOp.ts b/packages/queries/src/types/RefOp.ts index b86c249c..121a48a5 100644 --- a/packages/queries/src/types/RefOp.ts +++ b/packages/queries/src/types/RefOp.ts @@ -1,10 +1,10 @@ -import { Table } from './Table'; -import { JoinOp } from './JoinOp'; +import { Static, Type as t } from '@sinclair/typebox'; -export type RefOp = { - $ref: { - table: Table; - column: string; - op?: JoinOp; - }; -}; +export const RefOpSchema = t.Object({ + $ref: t.Object({ + table: t.String(), + column: t.String(), + }), +}); + +export type RefOp = Static; diff --git a/packages/queries/src/types/Select.ts b/packages/queries/src/types/Select.ts index 3e16d288..b9ed8230 100644 --- a/packages/queries/src/types/Select.ts +++ b/packages/queries/src/types/Select.ts @@ -1,6 +1,9 @@ +import { Static, Type as t, TSchema } from '@sinclair/typebox'; import { Table } from './Table'; import { Column } from './Column'; +export const SelectSchema = t.Record(t.String(), t.Optional(t.Boolean())); + /** * The type of a select clause in a query. */ diff --git a/packages/queries/src/types/Where.ts b/packages/queries/src/types/Where.ts index d181f1b4..b171f529 100644 --- a/packages/queries/src/types/Where.ts +++ b/packages/queries/src/types/Where.ts @@ -1,6 +1,9 @@ -import { Table } from './Table'; +import { Type as t } from '@sinclair/typebox'; import { Column } from './Column'; -import { WhereClause } from './WhereClause'; +import { Table } from './Table'; +import { WhereClause, WhereClauseSchema } from './WhereClause'; + +export const WhereSchema = t.Record(t.String(), WhereClauseSchema); /** * A where clause in a query. diff --git a/packages/queries/src/types/WhereClause.ts b/packages/queries/src/types/WhereClause.ts index e068f7b4..1e4899f1 100644 --- a/packages/queries/src/types/WhereClause.ts +++ b/packages/queries/src/types/WhereClause.ts @@ -1,8 +1,15 @@ -import { Table } from './Table'; +import { Type as t } from '@sinclair/typebox'; +import { BinaryOp, BinaryOpSchema } from './BinaryOp'; import { Column } from './Column'; -import { ColumnValue } from './ColumnValue'; -import { RefOp } from './RefOp'; -import { BinaryOp } from './BinaryOp'; +import { ColumnValue, ColumnValueSchema } from './ColumnValue'; +import { RefOp, RefOpSchema } from './RefOp'; +import { Table } from './Table'; + +export const WhereClauseSchema = t.Union([ + ColumnValueSchema, + BinaryOpSchema, + RefOpSchema, +]); export type WhereClause< DB, diff --git a/packages/queries/src/types/types.ts b/packages/queries/src/types/types.ts index 98818ef5..018e6d9d 100644 --- a/packages/queries/src/types/types.ts +++ b/packages/queries/src/types/types.ts @@ -1,19 +1,26 @@ -import { Table } from './Table'; -import { Select } from './Select'; -import { Where } from './Where'; -import { Include } from './Include'; -import { Cardinality } from './Cardinality'; +import { Static, Type as t, TSchema } from '@sinclair/typebox'; +import { CardinalitySchema } from './Cardinality'; +import { SelectSchema } from './Select'; +import { WhereSchema } from './Where'; -export type Query = Table> = { - from: TTable; - select: Select; - where: Where; - include?: Include; - limit?: number; - offset?: number; - cardinality?: Cardinality; - lazy?: true; - groupBy?: string[]; - hash?: string; - name?: string; -}; +export const QuerySchema = t.Recursive((self) => + t.Object({ + from: t.String(), + lazy: t.Optional(t.Boolean()), + select: SelectSchema, + include: t.Optional(t.Record(t.String(), self)), + where: WhereSchema, + cardinality: t.Optional(CardinalitySchema), + schema: t.Optional(t.Unknown()), + limit: t.Optional(t.Number()), + offset: t.Optional(t.Number()), + hash: t.Optional(t.String()), + name: t.Optional(t.String()), + groupBy: t.Optional(t.Array(t.String())), + }), +); +export type Query< + DB = any, + TTable = any, + TQueryResult extends TSchema = any, +> = Static & { schema?: TQueryResult }; diff --git a/packages/queries/src/util/hashQuery.ts b/packages/queries/src/util/hashQuery.ts index 44c1a1b2..87200280 100644 --- a/packages/queries/src/util/hashQuery.ts +++ b/packages/queries/src/util/hashQuery.ts @@ -1,4 +1,4 @@ -import { AnyQuery } from '../types/AnyQuery'; +import { Query } from '../types/types'; import { isQueryParameter } from '../validators/isQueryParam'; // Copied from: https://github.com/TanStack/query/blob/353e4ad7291645f27de6585e9897b45e46c666fb/packages/query-core/src/utils.ts#L205 @@ -6,7 +6,7 @@ import { isQueryParameter } from '../validators/isQueryParam'; * Default query & mutation keys hash function. * Hashes the value into a stable hash. */ -export function hashQuery(query: AnyQuery): string { +export function hashQuery(query: Omit): string { return djb2Hash( JSON.stringify(query, (_, val) => { if (isQueryParameter(val)) { diff --git a/packages/queries/src/validators/validateNestedQueriesHaveAValidRefOp.ts b/packages/queries/src/validators/validateNestedQueriesHaveAValidRefOp.ts index 281de11d..7a81434f 100644 --- a/packages/queries/src/validators/validateNestedQueriesHaveAValidRefOp.ts +++ b/packages/queries/src/validators/validateNestedQueriesHaveAValidRefOp.ts @@ -1,16 +1,17 @@ import { QueryBuilderError } from '../QueryBuilderError'; -import { Query } from '../types/types'; +import { AnyQuery } from '../types/AnyQuery'; import { isRefOp } from './isRefOp'; /** Validate that every included sub-query has at least one RefOp */ -export function validateNestedQueriesHaveAValidRefOp(query: Query) { +export function validateNestedQueriesHaveAValidRefOp( + query: Omit, +) { const nestedQueries = Object.values(query.include ?? {}); for (const nestedQuery of nestedQueries) { const whereClauses = Object.values(nestedQuery.where); - if (!whereClauses.some((whereClause) => isRefOp(whereClause))) { throw QueryBuilderError.createNestedQueryMissingRefOpWhereClauseError( { diff --git a/packages/react/package.json b/packages/react/package.json index c58ac618..94ae8bee 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -23,7 +23,7 @@ "build": "vite build --mode production", "checks": "yarn vitest run && yarn tsc", "publish:minor": "yarn publish --access public --no-git-tag-version", - "format": "yarn prettier --config ../../prettier.config.js --write ./src/", + "format": "yarn prettier --config ../../.prettierrc.js --write ./src/", "compile-executable-examples": "node ../../scripts/compile-executable-examples.cjs ./src/useSynthql.test.tsx" }, "dependencies": { diff --git a/packages/react/src/SynthqlQueryCache.ts b/packages/react/src/SynthqlQueryCache.ts deleted file mode 100644 index 17461d9f..00000000 --- a/packages/react/src/SynthqlQueryCache.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { Query, QueryCache } from '@tanstack/react-query'; - -type QueryCacheConfig = ConstructorParameters[0]; - -export function createXqlQueryCache(opts: QueryCacheConfig) { - return new XqlQueryCache(opts); -} - -class XqlQueryCache extends QueryCache { - add(query: Query): void { - super.add(query); - } -} diff --git a/packages/react/src/synthqlQueryKey.ts b/packages/react/src/synthqlQueryKey.ts index 74b9bd60..1ae98133 100644 --- a/packages/react/src/synthqlQueryKey.ts +++ b/packages/react/src/synthqlQueryKey.ts @@ -14,14 +14,10 @@ export type SynthqlQueryKey< | readonly ['synthql', TQuery] | readonly ['synthql', TQuery, SynthqlQueryOptions]; -export function synthqlQueryKey< - DB, - TTable extends Table, - TQuery extends Query, ->( +export function synthqlQueryKey( query: TQuery, opts?: SynthqlQueryOptions, -): SynthqlQueryKey { +): SynthqlQueryKey { if (opts) { return ['synthql', query, opts]; } @@ -29,7 +25,9 @@ export function synthqlQueryKey< return ['synthql', query]; } -export function isSynthqlQueryKey(key: QueryKey | SynthqlQueryKey): boolean { +export function isSynthqlQueryKey( + key: QueryKey | SynthqlQueryKey, +): key is SynthqlQueryKey { if (key.length < 1) { return false; } diff --git a/packages/react/src/useSynthql.test.tsx b/packages/react/src/useSynthql.test.tsx index b60b7c61..e549c14c 100644 --- a/packages/react/src/useSynthql.test.tsx +++ b/packages/react/src/useSynthql.test.tsx @@ -1,18 +1,14 @@ +import { QueryEngine } from '@synthql/backend'; +import { col, Query } from '@synthql/queries'; +import { renderHook } from '@testing-library/react-hooks'; import React from 'react'; import { afterAll, beforeAll, describe, expect, test } from 'vitest'; -import { renderHook } from '@testing-library/react-hooks'; import { useSynthql } from '.'; -import { PagilaServer, createPagilaServer } from './test/createPagilaServer'; -import { DB, from } from './test/generated'; +import { createPagilaServer, PagilaServer } from './test/createPagilaServer'; +import { from } from './test/generated'; import { Providers } from './test/Providers'; -import { QueryEngine } from '@synthql/backend'; -import { col, Query, Table } from '@synthql/queries'; -function renderSynthqlQuery< - DB, - TTable extends Table, - TQuery extends Query, ->({ +function renderSynthqlQuery({ query, returnLastOnly, server, @@ -23,7 +19,7 @@ function renderSynthqlQuery< }) { const result = renderHook( () => { - const result = useSynthql(query, { + const result = useSynthql(query, { returnLastOnly, }); @@ -64,7 +60,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, server: pagilaServer, }); @@ -90,7 +86,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, server: pagilaServer, }); @@ -114,7 +110,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, server: pagilaServer, }); @@ -139,7 +135,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, server: pagilaServer, }); @@ -164,7 +160,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, server: pagilaServer, }); @@ -197,7 +193,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, server: pagilaServer, }); @@ -236,7 +232,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, server: pagilaServer, }); @@ -332,7 +328,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, server: pagilaServer, }); @@ -400,7 +396,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, returnLastOnly: true, server: pagilaServer, @@ -484,7 +480,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, returnLastOnly: true, server: pagilaServer, @@ -582,7 +578,7 @@ describe('useSynthql', () => { // @@end-example@@ - const result = renderSynthqlQuery({ + const result = renderSynthqlQuery({ query: q, returnLastOnly: true, server: pagilaServer, diff --git a/packages/react/src/useSynthql.ts b/packages/react/src/useSynthql.ts index c99c8a7e..403b9f62 100644 --- a/packages/react/src/useSynthql.ts +++ b/packages/react/src/useSynthql.ts @@ -1,28 +1,20 @@ -import { Query, QueryResult, Table } from '@synthql/queries'; -import { useSynthqlContext } from './SynthqlProvider'; -import { useAyncGeneratorQuery } from './useAsyncGeneratorQuery'; -import { synthqlQueryKey } from './synthqlQueryKey'; +import { Query, QueryResult } from '@synthql/queries'; import { QueryOptions, UseQueryResult } from '@tanstack/react-query'; import { fetchJsonLines } from './fetchJsonLines'; +import { useSynthqlContext } from './SynthqlProvider'; +import { synthqlQueryKey } from './synthqlQueryKey'; +import { useAyncGeneratorQuery } from './useAsyncGeneratorQuery'; -type SynthqlQueryOptions< - DB, - TTable extends Table, - TQuery extends Query, -> = { +type SynthqlQueryOptions = { requestInit?: RequestInit; returnLastOnly?: boolean; - reactQuery?: Pick>, 'retry'>; + reactQuery?: QueryOptions; }; -export function useSynthql< - DB, - TTable extends Table, - TQuery extends Query, ->( +export function useSynthql( query: TQuery, - opts: SynthqlQueryOptions = {}, -): UseQueryResult> { + opts: SynthqlQueryOptions = {}, +): UseQueryResult> { const { endpoint, requestInit } = useSynthqlContext(); const enrichedEndpoint = `${endpoint}/${query.name ?? query.from}-${query.hash}`; @@ -37,7 +29,7 @@ export function useSynthql< body: JSON.stringify(query), }; - const queryKey = synthqlQueryKey(query, { + const queryKey = synthqlQueryKey(query, { endpoint: enrichedEndpoint, requestInit: mergedRequestInit, }); @@ -45,7 +37,7 @@ export function useSynthql< return useAyncGeneratorQuery({ queryKey, queryFn: async () => { - return fetchJsonLines>( + return fetchJsonLines>( enrichedEndpoint, mergedRequestInit, ); diff --git a/packages/react/src/useSynthqlExamples.test.tsx b/packages/react/src/useSynthqlExamples.test.tsx index 7fc768a4..c89d94cc 100644 --- a/packages/react/src/useSynthqlExamples.test.tsx +++ b/packages/react/src/useSynthqlExamples.test.tsx @@ -1,9 +1,9 @@ +import { renderHook } from '@testing-library/react-hooks'; import React from 'react'; import { afterAll, beforeAll, describe, expect, test } from 'vitest'; -import { EchoServer, createEchoServer } from './test/createEchoServer'; -import { renderHook } from '@testing-library/react-hooks'; import { useSynthql } from '.'; -import { DB, from } from './test/echoDb'; +import { EchoServer, createEchoServer } from './test/createEchoServer'; +import { from } from './test/echoDb'; import { Providers } from './test/Providers'; describe('useSynthql test examples', () => { @@ -28,11 +28,10 @@ describe('useSynthql test examples', () => { // @@desc@@ Finds 0 or 1 record(s) in the `user` table where the `id` is in the list of ids const q = from('users') - .select({ id: true, name: true }) .where({ id: { in: ['1'] } }) .maybe(); - const result = useSynthql(q); + const result = useSynthql(q); // @@end-example@@ diff --git a/packages/ui/package.json b/packages/ui/package.json index a4b28f8a..0d0a97d4 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -6,7 +6,7 @@ "dev": "PORT=12345 next dev", "start": "next start", "lint": "next lint", - "format": "yarn prettier --config ../../prettier.config.js --write ./src/" + "format": "yarn prettier --config ../../.prettierrc.js --write ./src/" }, "dependencies": { "@emotion/react": "^11.11.3", diff --git a/scripts/compile-executable-examples.cjs b/scripts/compile-executable-examples.cjs index 4b71aca8..5ee9a988 100644 --- a/scripts/compile-executable-examples.cjs +++ b/scripts/compile-executable-examples.cjs @@ -102,7 +102,7 @@ function generateMarkdown(examples) { async function main() { const examples = parseTestFile(testFilePath); const prettierConfig = await prettier.resolveConfig( - path.join(__dirname, '../.prettier.config.js'), + path.join(__dirname, '../..prettierrc.js'), ); if (!prettierConfig) { diff --git a/yarn.lock b/yarn.lock index 54a6a8e4..b4fd5dbb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2587,6 +2587,11 @@ resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== +"@sinclair/typebox@^0.33.12": + version "0.33.12" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.33.12.tgz#1feac782bc50dc02733ad3d63964035dd3fe8ba7" + integrity sha512-d5KrXIdPolLp8VpGpZAQvEz8ioVtFlUQSyCIS2sEBi7FKhceIB7nj9BlNfqqvp5wmOfg8v8bP1rAvYYkjz21/Q== + "@sindresorhus/is@^4.6.0": version "4.6.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" From 7f7af168ed3080c3e72845099f6376df2441b804 Mon Sep 17 00:00:00 2001 From: Fernando Hurtado Date: Fri, 27 Sep 2024 21:08:32 +0200 Subject: [PATCH 2/7] wip --- packages/backend/src/QueryEngine.ts | 15 +++++---------- .../src/execution/composeExecutionResults.ts | 7 ++++--- packages/backend/src/execution/execute.ts | 5 +++-- .../src/query/collectColumnReferences.test.ts | 6 +++--- .../backend/src/query/iterateQuery.test.ts | 2 -- .../backend/src/query/iterateResultRow.test.ts | 7 +++---- packages/backend/src/tests/e2e/select.test.ts | 4 +--- .../src/tests/e2e/store-with-customers.test.ts | 8 ++++---- .../src/tests/e2e/store-with-films.test.ts | 3 +-- .../properties/cardinalityMany.test.ts | 3 +-- .../properties/cardinalityMaybe.test.ts | 3 +-- packages/backend/src/tests/queries.v2.ts | 2 +- ...s.timestamp-1727430152478-724472fcd03ee.mjs | 0 packages/queries/src/query.test.ts | 18 +++++++++++------- packages/queries/src/query.ts | 14 +++++--------- packages/queries/src/types/AnyQuery.ts | 3 +++ packages/queries/src/types/QueryResult.ts | 13 ++++++++++--- packages/queries/src/types/types.ts | 8 +++----- packages/react/src/synthqlQueryKey.ts | 2 +- packages/react/src/useSynthql.ts | 4 ++-- packages/ui/src/components/Editor/types.json | 4 ++-- 21 files changed, 64 insertions(+), 67 deletions(-) delete mode 100644 packages/cli/vite.config.ts.timestamp-1727430152478-724472fcd03ee.mjs diff --git a/packages/backend/src/QueryEngine.ts b/packages/backend/src/QueryEngine.ts index 0866d62e..a84fa4ae 100644 --- a/packages/backend/src/QueryEngine.ts +++ b/packages/backend/src/QueryEngine.ts @@ -96,7 +96,7 @@ export class QueryEngine { ]; } - execute, TQuery extends Query>( + execute( query: TQuery, opts?: { /** @@ -112,7 +112,7 @@ export class QueryEngine { */ returnLastOnly?: boolean; }, - ): AsyncGenerator> { + ): AsyncGenerator> { const gen = execute(query, { executors: this.executors, defaultSchema: opts?.schema ?? this.schema, @@ -126,10 +126,7 @@ export class QueryEngine { return gen; } - async executeAndWait< - TTable extends Table, - TQuery extends Query, - >( + async executeAndWait, TQuery extends Query>( query: TQuery, opts?: { /** @@ -140,7 +137,7 @@ export class QueryEngine { */ schema?: string; }, - ): Promise> { + ): Promise> { return await collectLast( generateLast( execute(query, { @@ -166,9 +163,7 @@ export class QueryEngine { return sqlBuilder.build(); } - async explain>( - query: Query, - ): Promise { + async explain>(query: Query): Promise { const { sqlBuilder } = composeQuery({ defaultSchema: this.schema, query, diff --git a/packages/backend/src/execution/composeExecutionResults.ts b/packages/backend/src/execution/composeExecutionResults.ts index cacc322d..54dcab21 100644 --- a/packages/backend/src/execution/composeExecutionResults.ts +++ b/packages/backend/src/execution/composeExecutionResults.ts @@ -1,5 +1,5 @@ import { Value } from '@sinclair/typebox/value'; -import { AnyDB, AnyTable, QueryResult } from '@synthql/queries'; +import { Query, QueryResult } from '@synthql/queries'; import { applyCardinality } from '../query/applyCardinality'; import { assertHasKey } from '../util/asserts/assertHasKey'; import { setIn } from '../util/tree/setIn'; @@ -7,7 +7,7 @@ import { ExecResultNode, ExecResultTree, ResultRow } from './types'; export function composeExecutionResults( tree: ExecResultTree, -): QueryResult { +): QueryResult { const queryResult: ResultRow[] = tree.root.result; for (const node of tree.root.children) { @@ -17,12 +17,13 @@ export function composeExecutionResults( const result = applyCardinality( queryResult, tree.root.inputQuery.cardinality ?? 'many', - ) as QueryResult; + ) as QueryResult; const schema = tree.root.inputQuery.schema; if (schema) { const error = Value.Errors(schema, [], result).First(); if (error) { + // TODO(fhur): Improve error message const lines = [ `${error.message} at path: ${error.path}`, `Value: ${JSON.stringify(error.value)}`, diff --git a/packages/backend/src/execution/execute.ts b/packages/backend/src/execution/execute.ts index eb0418e2..167b9208 100644 --- a/packages/backend/src/execution/execute.ts +++ b/packages/backend/src/execution/execute.ts @@ -36,10 +36,11 @@ export interface ExecuteProps { export async function* execute( query: TQuery, props: ExecuteProps, -): AsyncGenerator> { +): AsyncGenerator> { const plan = createExecutionPlan(query, props); for await (const resultTree of executePlan(plan, props)) { - yield composeExecutionResults(resultTree) as QueryResult; + // TODO(fhur) see if we can avoid this cast + yield composeExecutionResults(resultTree) as QueryResult; } } diff --git a/packages/backend/src/query/collectColumnReferences.test.ts b/packages/backend/src/query/collectColumnReferences.test.ts index 20d20306..f6c685da 100644 --- a/packages/backend/src/query/collectColumnReferences.test.ts +++ b/packages/backend/src/query/collectColumnReferences.test.ts @@ -1,6 +1,6 @@ -import { describe, expect, test } from 'vitest'; import { AnyQuery, QueryResult, col } from '@synthql/queries'; -import { DB, from } from '../tests/generated'; +import { describe, expect, test } from 'vitest'; +import { from } from '../tests/generated'; import { city } from '../tests/queries.v2'; import { collectColumnReferences } from './collectColumnReferences'; @@ -80,7 +80,7 @@ describe('collectColumnReferences', () => { .where({ city_id: col('address.city_id') }) .many(); - const queryResult: QueryResult = [ + const queryResult: QueryResult = [ { city: 'Bogota', city_id: 1 }, { city: 'Cali', city_id: 2 }, { city: 'Medellin', city_id: 3 }, diff --git a/packages/backend/src/query/iterateQuery.test.ts b/packages/backend/src/query/iterateQuery.test.ts index 465fbea9..d6d30bd5 100644 --- a/packages/backend/src/query/iterateQuery.test.ts +++ b/packages/backend/src/query/iterateQuery.test.ts @@ -194,7 +194,6 @@ describe('iterateQuery', () => { where: { film_id: 1, }, - schema: {}, }, expected: [ { @@ -202,7 +201,6 @@ describe('iterateQuery', () => { from: 'film', select: {}, where: { film_id: 1 }, - schema: {}, }, insertionPath: [], }, diff --git a/packages/backend/src/query/iterateResultRow.test.ts b/packages/backend/src/query/iterateResultRow.test.ts index 5ad9b35c..835f7fd2 100644 --- a/packages/backend/src/query/iterateResultRow.test.ts +++ b/packages/backend/src/query/iterateResultRow.test.ts @@ -1,8 +1,7 @@ +import { QueryResult, col } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; -import { iterateResultRows } from './iterateResultRow'; import { city } from '../tests/queries.v2'; -import { QueryResult, col } from '@synthql/queries'; -import { DB } from '../tests/generated'; +import { iterateResultRows } from './iterateResultRow'; describe('iterateResultRow', () => { test('iterateResultRow', () => { @@ -10,7 +9,7 @@ describe('iterateResultRow', () => { .where({ city_id: col('address.city_id') }) .many(); - const queryResult: QueryResult = [ + const queryResult: QueryResult = [ { city: 'Bogota', city_id: 1 }, { city: 'Cali', city_id: 2 }, { city: 'Medellin', city_id: 3 }, diff --git a/packages/backend/src/tests/e2e/select.test.ts b/packages/backend/src/tests/e2e/select.test.ts index d8cdee95..db50090c 100644 --- a/packages/backend/src/tests/e2e/select.test.ts +++ b/packages/backend/src/tests/e2e/select.test.ts @@ -7,9 +7,7 @@ import { findActorById, findCityById, from, movie } from '../queries'; import { queryEngine } from '../queryEngine'; describe('select', () => { - function run, T extends Query>( - query: T, - ) { + function run, T extends Query>(query: T) { return collectLast(queryEngine.execute(query)); } diff --git a/packages/backend/src/tests/e2e/store-with-customers.test.ts b/packages/backend/src/tests/e2e/store-with-customers.test.ts index b859894f..bfdd3d0c 100644 --- a/packages/backend/src/tests/e2e/store-with-customers.test.ts +++ b/packages/backend/src/tests/e2e/store-with-customers.test.ts @@ -5,7 +5,7 @@ import { execute } from '../../execution/execute'; import { PgExecutor } from '../../execution/executors/PgExecutor'; import { describeQuery } from '../../query/describeQuery'; import { assertPresent } from '../../util/asserts/assertPresent'; -import { DB, from } from '../generated'; +import { from } from '../generated'; import { sql } from '../postgres'; import { store } from '../queries.v2'; import { pool } from '../queryEngine'; @@ -13,17 +13,17 @@ import { sortRecursively } from '../sortRecursively'; describe('e2e', () => { const payments = from('payment') - .columns('payment_id', 'amount') .groupBy('payment_id', 'payment_date') + .columns('payment_id', 'amount') .where({ customer_id: col('customer.customer_id') }) .many(); const customers = from('customer') .columns('email', 'customer_id') - .where({ store_id: col('store.store_id'), customer_id: 367 }) .include({ payments, }) + .where({ store_id: col('store.store_id'), customer_id: 367 }) .many(); const q = store() @@ -46,7 +46,7 @@ describe('e2e', () => { // TODO: fix the test by fixing the sorting function and unskip test.skip(`${describeQuery(q)}`, async () => { - const rows: QueryResult[] = await sql` + const rows: QueryResult[] = await sql` SELECT s.store_id, JSON_AGG( diff --git a/packages/backend/src/tests/e2e/store-with-films.test.ts b/packages/backend/src/tests/e2e/store-with-films.test.ts index 23274677..459a7601 100644 --- a/packages/backend/src/tests/e2e/store-with-films.test.ts +++ b/packages/backend/src/tests/e2e/store-with-films.test.ts @@ -6,7 +6,6 @@ import { PgExecutor } from '../../execution/executors/PgExecutor'; import { describeQuery } from '../../query/describeQuery'; import { assertPresent } from '../../util/asserts/assertPresent'; import { compareInventory } from '../compareInventory'; -import { DB } from '../generated'; import { sql } from '../postgres'; import { actor, film, filmActor, inventory, store } from '../queries.v2'; import { pool } from '../queryEngine'; @@ -49,7 +48,7 @@ describe('e2e', () => { }; test(`${describeQuery(q)}`, async () => { - const rows: QueryResult[] = await sql` + const rows: QueryResult[] = await sql` SELECT s.store_id, jsonb_agg( diff --git a/packages/backend/src/tests/propertyBased/properties/cardinalityMany.test.ts b/packages/backend/src/tests/propertyBased/properties/cardinalityMany.test.ts index 49fa109b..3bcf39b9 100644 --- a/packages/backend/src/tests/propertyBased/properties/cardinalityMany.test.ts +++ b/packages/backend/src/tests/propertyBased/properties/cardinalityMany.test.ts @@ -1,5 +1,4 @@ import { it } from '@fast-check/vitest'; -import { Query } from '@synthql/queries'; import { describe, expect } from 'vitest'; import { DB, schema } from '../../generated'; import { pool, queryEngine } from '../../queryEngine'; @@ -24,7 +23,7 @@ describe('cardinalityMany', async () => { it.prop([validWhereArbitraryQuery], { verbose: 2 })( 'Valid where query should return possibly empty array', async (query) => { - const typedQuery = query as Query; + const typedQuery = query; const queryResult = await queryEngine.executeAndWait(typedQuery); diff --git a/packages/backend/src/tests/propertyBased/properties/cardinalityMaybe.test.ts b/packages/backend/src/tests/propertyBased/properties/cardinalityMaybe.test.ts index de1be957..68f4bf0a 100644 --- a/packages/backend/src/tests/propertyBased/properties/cardinalityMaybe.test.ts +++ b/packages/backend/src/tests/propertyBased/properties/cardinalityMaybe.test.ts @@ -1,5 +1,4 @@ import { it } from '@fast-check/vitest'; -import { Query } from '@synthql/queries'; import { describe, expect } from 'vitest'; import { DB, schema } from '../../generated'; import { pool, queryEngine } from '../../queryEngine'; @@ -49,7 +48,7 @@ describe('cardinalityMaybe', async () => { it.skip.prop([invalidWhereArbitraryQuery], { verbose: 2 })( 'Invalid where query should return null', async (query) => { - const typedQuery = query as Query; + const typedQuery = query; const queryResult = await queryEngine.executeAndWait(typedQuery); diff --git a/packages/backend/src/tests/queries.v2.ts b/packages/backend/src/tests/queries.v2.ts index 65cf99ac..829041cc 100644 --- a/packages/backend/src/tests/queries.v2.ts +++ b/packages/backend/src/tests/queries.v2.ts @@ -10,7 +10,7 @@ export function actor() { } export function filmActor() { - return from('film_actor').columns().groupBy('actor_id', 'film_id'); + return from('film_actor').groupBy('actor_id', 'film_id').columns(); } export function film() { diff --git a/packages/cli/vite.config.ts.timestamp-1727430152478-724472fcd03ee.mjs b/packages/cli/vite.config.ts.timestamp-1727430152478-724472fcd03ee.mjs deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/queries/src/query.test.ts b/packages/queries/src/query.test.ts index 3e4dc89e..831b79a8 100644 --- a/packages/queries/src/query.test.ts +++ b/packages/queries/src/query.test.ts @@ -1,9 +1,9 @@ import { describe, test } from 'vitest'; import { AnyQuery, Query, QueryResult, col } from '.'; -import { DB, from } from './generated'; +import { from } from './generated'; describe('queries', () => { - function fakeQueryResult(q: T): QueryResult { + function fakeQueryResult(q: T): QueryResult { return {} as any; } @@ -118,8 +118,8 @@ describe('queries', () => { test('Find film with language and actors', () => { const language = from('language') - .where({ language_id: col('film.language_id') }) .columns('language_id', 'name') + .where({ language_id: col('film.language_id') }) .maybe(); const filmActor = from('film_actor') @@ -178,7 +178,12 @@ describe('queries', () => { address, }) .include({ - address: from('address').columns('address2').one(), + address: from('address') + .columns('address2') + .where({ + address_id: col('store.address_id'), + }) + .many(), }) .include({ staff, @@ -188,9 +193,8 @@ describe('queries', () => { const result = fakeQueryResult(store); result satisfies Array<{ address_id: number; - address: { - address_id: number; - city_id: number; + staff: { + staff_id: number; }; }>; }); diff --git a/packages/queries/src/query.ts b/packages/queries/src/query.ts index 138a8a4c..72e3bb70 100644 --- a/packages/queries/src/query.ts +++ b/packages/queries/src/query.ts @@ -30,8 +30,8 @@ export class QueryBuilder< private schema: TResultSchema, ) {} - private build(): Query { - const built: Query = assertQuery( + private build(): Query { + const built: Query = assertQuery( this.query, this.schema, ); @@ -143,7 +143,7 @@ export class QueryBuilder< /** * @alias {@link all} */ - many(): Query> { + many(): Query> { const query = this.query; const schema = t.Array(this.schema); @@ -345,7 +345,7 @@ export function query(schema: Schema) { function assertQuery( partialQuery: Partial, schema: T, -): Query { +): Query { Assert(QuerySchema, partialQuery); return { ...partialQuery, schema }; @@ -359,11 +359,7 @@ type AppendToSchema = SchemaOf< Append< Static, { - [key in keyof TInclude]: TInclude[key] extends Query< - any, - any, - infer T - > + [key in keyof TInclude]: TInclude[key] extends Query ? Static : unknown; } diff --git a/packages/queries/src/types/AnyQuery.ts b/packages/queries/src/types/AnyQuery.ts index afce5449..80367493 100644 --- a/packages/queries/src/types/AnyQuery.ts +++ b/packages/queries/src/types/AnyQuery.ts @@ -15,4 +15,7 @@ export type AnyTableDef = { }; export type AnyDB = Record; export type AnyTable = string; +/** + * @deprecated: just use Query + */ export type AnyQuery = Query; diff --git a/packages/queries/src/types/QueryResult.ts b/packages/queries/src/types/QueryResult.ts index a2b30404..ad1457e1 100644 --- a/packages/queries/src/types/QueryResult.ts +++ b/packages/queries/src/types/QueryResult.ts @@ -1,9 +1,16 @@ import { Static } from '@sinclair/typebox'; import { Query } from './types'; -export type QueryResult = - TQuery extends Query +export type QueryResult = + TQuery extends Query ? Simplify> : unknown; -type Simplify = T extends object ? { [K in keyof T]: Simplify } : T; +type Simplify = + T extends Array + ? Simplify[] + : T extends Date + ? T + : T extends object + ? { [K in keyof T]: Simplify } + : T; diff --git a/packages/queries/src/types/types.ts b/packages/queries/src/types/types.ts index 018e6d9d..bcfd13b9 100644 --- a/packages/queries/src/types/types.ts +++ b/packages/queries/src/types/types.ts @@ -19,8 +19,6 @@ export const QuerySchema = t.Recursive((self) => groupBy: t.Optional(t.Array(t.String())), }), ); -export type Query< - DB = any, - TTable = any, - TQueryResult extends TSchema = any, -> = Static & { schema?: TQueryResult }; +export type Query = Static< + typeof QuerySchema +> & { schema?: TQueryResult }; diff --git a/packages/react/src/synthqlQueryKey.ts b/packages/react/src/synthqlQueryKey.ts index 1ae98133..886f4f06 100644 --- a/packages/react/src/synthqlQueryKey.ts +++ b/packages/react/src/synthqlQueryKey.ts @@ -9,7 +9,7 @@ interface SynthqlQueryOptions { export type SynthqlQueryKey< DB = any, TTable extends Table = any, - TQuery extends Query = Query, + TQuery extends Query = Query, > = | readonly ['synthql', TQuery] | readonly ['synthql', TQuery, SynthqlQueryOptions]; diff --git a/packages/react/src/useSynthql.ts b/packages/react/src/useSynthql.ts index 403b9f62..aedd6954 100644 --- a/packages/react/src/useSynthql.ts +++ b/packages/react/src/useSynthql.ts @@ -14,7 +14,7 @@ type SynthqlQueryOptions = { export function useSynthql( query: TQuery, opts: SynthqlQueryOptions = {}, -): UseQueryResult> { +): UseQueryResult> { const { endpoint, requestInit } = useSynthqlContext(); const enrichedEndpoint = `${endpoint}/${query.name ?? query.from}-${query.hash}`; @@ -37,7 +37,7 @@ export function useSynthql( return useAyncGeneratorQuery({ queryKey, queryFn: async () => { - return fetchJsonLines>( + return fetchJsonLines>( enrichedEndpoint, mergedRequestInit, ); diff --git a/packages/ui/src/components/Editor/types.json b/packages/ui/src/components/Editor/types.json index 984c2340..21b383d5 100644 --- a/packages/ui/src/components/Editor/types.json +++ b/packages/ui/src/components/Editor/types.json @@ -1,12 +1,12 @@ [ { "module": "backend", - "types": "\n\n\n\n/// \ndeclare module \"@synthql/backend/src/types/index\" {\n import { JoinOp, Query } from '@synthql/queries';\n import { BinaryOperator } from 'kysely';\n export type AnyDb = Record>;\n export type AnyQuery = Query;\n export type AnyTable = string;\n export type Cardinality = 'one' | 'maybe' | 'many';\n export interface AugmentedQuery {\n /**\n * A unique identifier for the query, inside the query tree.\n */\n id: string;\n /**\n * A reference to the query that was augmented\n */\n query: AnyQuery;\n depth: number;\n /**\n * The table that the query is selecting from\n */\n from: AugmentedTable;\n /**\n * The columns that the query is selecting.\n */\n select: Array;\n /**\n * The where clause of the query.\n */\n where: Array;\n children: AugmentedQuery[];\n leftJoin?: {\n joinOp: JoinOp;\n joinTable: AugmentedTable;\n ownColumn: AugmentedColumn;\n otherColumn: AugmentedColumn;\n };\n }\n type WhereOp = WhereBinaryOp | WhereRefOp;\n export type OpValue = {\n type: 'column';\n column: AugmentedColumn;\n } | {\n type: 'value';\n value: any;\n };\n export interface WhereBinaryOp {\n type: 'binary';\n lhs: OpValue;\n op: BinaryOperator;\n rhs: OpValue;\n }\n interface WhereRefOp {\n type: 'ref';\n lhs: AugmentedColumn;\n rhs: AugmentedColumn;\n }\n export interface SelectionColumn {\n type: 'column';\n column: string;\n /**\n * A unique identifier for the column, inside the query result.\n * Example:\n *\n * ```\n * select table.alias.column as id\n * from ...\n * ```\n */\n id: string;\n table: AugmentedTable;\n }\n export function isSelectionColumn(selection: SelectionColumn | SelectionJsonbAgg): selection is SelectionColumn;\n export function isSelectionJsonbAgg(selection: SelectionColumn | SelectionJsonbAgg): selection is SelectionJsonbAgg;\n interface SelectionJsonbAgg {\n type: 'jsonb_agg';\n id: string;\n table: AugmentedTable;\n columns: SelectionColumn[];\n includeColumn: string;\n }\n export interface AugmentedTable {\n alias: string;\n name: string;\n schema: string;\n }\n export interface AugmentedColumn {\n column: string;\n table: AugmentedTable;\n }\n}\ndeclare module \"@synthql/backend/src/cache\" {\n import { Query, QueryResult, Table } from '@synthql/queries';\n export class QueryCache {\n private cache;\n set>(query: Query, result: QueryResult): void;\n get>(query: Query): QueryResult | undefined;\n }\n export function isPlainObject(o: any): o is Object;\n}\ndeclare module \"@synthql/backend/src/escape\" {\n export function escapeColumn(col: string): string;\n}\ndeclare module \"@synthql/backend/src/util/collectFirst\" {\n export function collectFirst(gen: AsyncGenerator): Promise;\n}\ndeclare module \"@synthql/backend/src/types/QueryPlan\" {\n export interface QueryPlan {\n 'Execution Time'?: number;\n 'Planning Time'?: number;\n 'Settings': {};\n 'Triggers': [];\n 'Planning': Planning;\n 'Plan': PlanNode;\n }\n interface Planning {\n 'Local Dirtied Blocks': number;\n 'Local Hit Blocks': number;\n 'Local Read Blocks': number;\n 'Local Written Blocks': number;\n 'Shared Dirtied Blocks': number;\n 'Shared Hit Blocks': number;\n 'Shared Read Blocks': number;\n 'Shared Written Blocks': number;\n 'Temp Read Blocks': number;\n 'Temp Written Blocks': number;\n }\n type PlanNode = PlanLimit | PlanAggregate | PlanNestedLoop | PlanSeqScan | PlanIndexScan;\n interface BasePlan {\n 'Actual Loops': number;\n 'Actual Rows': number;\n 'Actual Startup Time'?: number;\n 'Actual Total Time'?: number;\n 'Local Dirtied Blocks': number;\n 'Local Hit Blocks': number;\n 'Local Read Blocks': number;\n 'Alias'?: string;\n 'Local Written Blocks': number;\n 'Output': string[];\n 'Parallel Aware': boolean;\n 'Plan Rows': number;\n 'Plan Width': number;\n 'Plans'?: PlanNode[];\n 'Shared Dirtied Blocks': number;\n 'Shared Hit Blocks': number;\n 'Shared Read Blocks': number;\n 'Shared Written Blocks': number;\n 'Startup Cost': number;\n 'Total Cost': number;\n 'Temp Read Blocks': number;\n 'Temp Written Blocks': number;\n }\n interface PlanLimit extends BasePlan {\n 'Node Type': 'Limit';\n }\n interface PlanAggregate extends BasePlan {\n 'Node Type': 'Aggregate';\n 'Group Key': string[];\n 'Parent Relationship': 'Outer' | 'Inner';\n 'Partial Mode': 'Simple' | 'Hashed' | 'Mixed';\n 'Strategy': 'Plain' | 'Sorted';\n }\n interface PlanNestedLoop extends BasePlan {\n 'Node Type': 'Nested Loop';\n 'Inner Unique': boolean;\n 'Join Type': 'Left' | 'Inner';\n 'Parent Relationship': 'Outer' | 'Inner';\n 'Shared Dirtied Blocks': number;\n 'Shared Hit Blocks': number;\n 'Shared Read Blocks': number;\n 'Shared Written Blocks': number;\n 'Startup Cost': number;\n 'Total Cost': number;\n 'Temp Read Blocks': number;\n 'Temp Written Blocks': number;\n }\n interface PlanSeqScan extends BasePlan {\n 'Node Type': 'Seq Scan';\n 'Relation Name': string;\n }\n interface PlanIndexScan extends BasePlan {\n 'Node Type': 'Index Scan';\n 'Index Name': string;\n 'Scan Direction': 'Forward' | 'Backward';\n 'Relation Name': string;\n 'Schema': string;\n 'Index Cond'?: string;\n 'Parent Relationship': 'Outer' | 'Inner';\n 'Rows Removed by Index Recheck'?: number;\n }\n}\ndeclare module \"@synthql/backend/src/AugmentedQuery/iterateAugmentedQuery\" {\n import { AugmentedQuery } from \"@synthql/backend/src/types/index\";\n export function iterateAugmentedQuery(query: AugmentedQuery): Generator;\n}\ndeclare module \"@synthql/backend/src/util/isPresent\" {\n export function isPresent(value: T | null | undefined): value is T;\n export function isString(value: unknown): value is string;\n}\ndeclare module \"@synthql/backend/src/AugmentedQuery/augmentQuery\" {\n import { AnyQuery, AugmentedQuery } from \"@synthql/backend/src/types/index\";\n interface AugmentOpts {\n defaultSchema: string;\n depth?: number;\n nodeId?: string;\n includeColumn?: string;\n }\n export function augmentQuery(query: AnyQuery, opts: AugmentOpts): AugmentedQuery;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/composeQuery\" {\n import { Kysely, SelectQueryBuilder } from 'kysely';\n import { AnyQuery, AugmentedQuery } from \"@synthql/backend/src/types/index\";\n export function composeQuery({ defaultSchema, db, query, }: {\n defaultSchema: string;\n db: Kysely;\n query: AnyQuery;\n }): {\n kQuery: SelectQueryBuilder;\n rootQuery: AugmentedQuery;\n };\n}\ndeclare module \"@synthql/backend/src/util/asserts\" {\n export function assertArrayInResult(value: unknown, path: string): Array<{\n [key: string]: any;\n }>;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/applyCardinality\" {\n import { AnyQuery, Cardinality } from \"@synthql/backend/src/types/index\";\n type CardinalityResult = TCardinality extends 'one' ? T : TCardinality extends 'maybe' ? T | null : T[];\n export function applyCardinality(result: Array, cardinality: TCardinality, opts?: {\n query: AnyQuery;\n row: any;\n }): CardinalityResult;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/hydrate\" {\n import { AugmentedQuery } from \"@synthql/backend/src/types/index\";\n interface Row {\n [key: string]: any;\n }\n type AnyQueryResult = undefined | Array | {\n [key: string]: any;\n };\n export function hydrate(data: Array, query: AugmentedQuery): AnyQueryResult;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/QueryEngine\" {\n import { CompiledQuery } from 'kysely';\n import { Pool } from 'pg';\n import { Query, QueryResult, Table } from \"@synthql/queries\";\n import { QueryPlan } from \"@synthql/backend/src/index\";\n export interface QueryProvider> {\n table: TTable;\n execute: >(query: TQuery) => Promise>;\n }\n export interface QueryEngineProps {\n url?: string;\n schema?: string;\n providers?: Array>;\n pool?: Pool;\n }\n export class QueryEngine {\n private dialect;\n private db;\n private pool;\n private schema;\n constructor(config: QueryEngineProps);\n execute, TQuery extends Query>(query: TQuery, opts?: {\n schema?: string;\n }): AsyncGenerator>;\n compile(query: T extends Query ? T : never): CompiledQuery;\n explain>(query: Query): Promise;\n private tryToExecute;\n }\n}\ndeclare module \"@synthql/backend/src/index\" {\n export { collectFirst } from \"@synthql/backend/src/util/collectFirst\";\n export type * from \"@synthql/backend/src/types/QueryPlan\";\n export * from \"@synthql/backend/src/AugmentedQuery/iterateAugmentedQuery\";\n export * from \"@synthql/backend/src/QueryEngine/QueryEngine\";\n}\ndeclare module \"@synthql/backend/src/generateSchema\" {\n import { QueryEngine } from \"@synthql/backend/src/index\";\n export interface PgSchema {\n 'information_schema.tables': {\n table_name: string;\n table_schema: string;\n };\n 'information_schema.columns': {\n column_name: string;\n table_name: string;\n table_schema: string;\n data_type: string;\n is_nullable: 'YES' | 'NO';\n udt_name: string;\n udt_schema: string;\n column_default: string | null;\n };\n 'pg_catalog.pg_type': {\n typname: string;\n oid: number;\n };\n 'pg_catalog.pg_enum': {\n enumtypid: number;\n enumlabel: string;\n enumsortorder: number;\n oid: number;\n };\n }\n export type GenerateSchemaConfig = {\n schemas: string[];\n };\n export function generateSchema(queryEngine: QueryEngine, config: GenerateSchemaConfig): Promise<{\n tables: ({\n table_name: string;\n table_schema: string;\n } & {\n columns: ({\n column_name: string;\n data_type: string;\n is_nullable: \"YES\" | \"NO\";\n udt_name: string;\n udt_schema: string;\n } & {})[];\n })[];\n enums: ({\n typname: string;\n } & {\n enumValues: ({\n enumlabel: string;\n } & {})[];\n })[];\n }>;\n}\ndeclare module \"@synthql/backend/src/tests/db\" {\n import type { ColumnType } from 'kysely';\n export type Generated = T extends ColumnType ? ColumnType : ColumnType;\n export type MpaaRating = 'G' | 'NC-17' | 'PG' | 'PG-13' | 'R';\n export type Numeric = ColumnType;\n export type Timestamp = ColumnType;\n export interface Actor {\n actor_id: Generated;\n first_name: string;\n last_name: string;\n last_update: Generated;\n }\n export interface ActorInfo {\n actor_id: number | null;\n film_info: string | null;\n first_name: string | null;\n last_name: string | null;\n }\n export interface Address {\n address: string;\n address_id: Generated;\n address2: string | null;\n city_id: number;\n district: string;\n last_update: Generated;\n phone: string;\n postal_code: string | null;\n }\n export interface Category {\n category_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface City {\n city: string;\n city_id: Generated;\n country_id: number;\n last_update: Generated;\n }\n export interface Country {\n country: string;\n country_id: Generated;\n last_update: Generated;\n }\n export interface Customer {\n active: number | null;\n activebool: Generated;\n address_id: number;\n create_date: Generated;\n customer_id: Generated;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n store_id: number;\n }\n export interface CustomerList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'notes': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Film {\n description: string | null;\n film_id: Generated;\n fulltext: string;\n language_id: number;\n last_update: Generated;\n length: number | null;\n original_language_id: number | null;\n rating: Generated;\n release_year: number | null;\n rental_duration: Generated;\n rental_rate: Generated;\n replacement_cost: Generated;\n special_features: string[] | null;\n title: string;\n }\n export interface FilmActor {\n actor_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmCategory {\n category_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface Inventory {\n film_id: number;\n inventory_id: Generated;\n last_update: Generated;\n store_id: number;\n }\n export interface Language {\n language_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface NicerButSlowerFilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface PaymentP202201 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202202 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202203 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202204 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202205 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202206 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202207 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface Rental {\n customer_id: number;\n inventory_id: number;\n last_update: Generated;\n rental_date: Timestamp;\n rental_id: Generated;\n return_date: Timestamp | null;\n staff_id: number;\n }\n export interface SalesByFilmCategory {\n category: string | null;\n total_sales: Numeric | null;\n }\n export interface SalesByStore {\n manager: string | null;\n store: string | null;\n total_sales: Numeric | null;\n }\n export interface Staff {\n active: Generated;\n address_id: number;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n password: string | null;\n picture: Buffer | null;\n staff_id: Generated;\n store_id: number;\n username: string;\n }\n export interface StaffList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Store {\n address_id: number;\n last_update: Generated;\n manager_staff_id: number;\n store_id: Generated;\n }\n export interface DB {\n actor: Actor;\n actor_info: ActorInfo;\n address: Address;\n category: Category;\n city: City;\n country: Country;\n customer: Customer;\n customer_list: CustomerList;\n film: Film;\n film_actor: FilmActor;\n film_category: FilmCategory;\n film_list: FilmList;\n inventory: Inventory;\n language: Language;\n nicer_but_slower_film_list: NicerButSlowerFilmList;\n payment_p2022_01: PaymentP202201;\n payment_p2022_02: PaymentP202202;\n payment_p2022_03: PaymentP202203;\n payment_p2022_04: PaymentP202204;\n payment_p2022_05: PaymentP202205;\n payment_p2022_06: PaymentP202206;\n payment_p2022_07: PaymentP202207;\n rental: Rental;\n sales_by_film_category: SalesByFilmCategory;\n sales_by_store: SalesByStore;\n staff: Staff;\n staff_list: StaffList;\n store: Store;\n }\n}\ndeclare module \"@synthql/backend/src/tests/queryEngine\" {\n import { QueryEngine } from \"@synthql/backend/src/QueryEngine/QueryEngine\";\n import { DB } from \"@synthql/backend/src/tests/db\";\n export const queryEngine: QueryEngine;\n}\ndeclare module \"@synthql/backend/src/generateSchema.test\" { }\ndeclare module \"@synthql/backend/src/tests/postgres\" {\n import pg from 'postgres';\n export const sql: pg.Sql<{}>;\n}\ndeclare module \"@synthql/backend/src/tests/queries\" {\n import { Table, WhereClause } from '@synthql/queries';\n import { DB } from \"@synthql/backend/src/tests/db\";\n export function from>(table: TTable): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function actor(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function findActorById(actorId: number): {\n from: \"actor\";\n where: {\n actor_id: number;\n };\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n export function findActors(): {\n from: \"actor\";\n where: {};\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n export function language(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function findLanguageById(id: WhereClause): import(\"@synthql/queries/src/query\").QueryBuilder;\n }, \"many\", {}, {\n language_id: true;\n name: true;\n last_update: true;\n }, undefined, [\"language_id\"]>;\n export function movie(): import(\"@synthql/queries/src/query\").QueryBuilder;\n };\n select: {\n language_id: true;\n name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"language_id\"];\n };\n film_actor: {\n from: \"film_actor\";\n where: {\n film_id: import(\"@synthql/queries\").RefOp;\n };\n select: {};\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"id\"];\n };\n actors: {\n from: \"actor\";\n where: {\n actor_id: import(\"@synthql/queries\").RefOp;\n };\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n }, {\n title: true;\n description: true;\n release_year: true;\n }, undefined, [\"film_id\"]>;\n export function country(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function city(): import(\"@synthql/queries/src/query\").QueryBuilder;\n };\n select: {\n country_id: true;\n country: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"country_id\"];\n };\n }, {\n city_id: true;\n city: true;\n last_update: true;\n country_id: true;\n }, undefined, [\"city_id\"]>;\n export function findCityById(id: WhereClause): {\n from: \"city\";\n where: {\n city_id: WhereClause;\n };\n select: {\n city_id: true;\n city: true;\n last_update: true;\n country_id: true;\n };\n include: {\n country: {\n from: \"country\";\n where: {\n country_id: WhereClause;\n };\n select: {\n country_id: true;\n country: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"country_id\"];\n };\n };\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: undefined;\n groupingId: [\"city_id\"];\n };\n}\ndeclare module \"@synthql/backend/src/tests/select.test\" { }\ndeclare module \"@synthql/backend/src/util/collectAsync\" {\n export function collectAsync(gen: AsyncGenerator): Promise;\n}\n/**\n * Performs a LEFT JOIN on two arrays using a hash table.\n */\ndeclare function hashLeftJoin(left: TLeft[], right: TRight[], leftKey: (l: TLeft) => string, rightKey: (r: TRight) => string): Array<[TLeft, TRight | undefined]>;\n\n\n declare module \"@synthql/backend\" { export * from \"@synthql/backend/src/index\"; }", + "types": "\n\n\n\n/// \ndeclare module \"@synthql/backend/src/types/index\" {\n import { JoinOp, Query } from '@synthql/queries';\n import { BinaryOperator } from 'kysely';\n export type AnyDb = Record>;\n export type AnyQuery = Query;\n export type AnyTable = string;\n export type Cardinality = 'one' | 'maybe' | 'many';\n export interface AugmentedQuery {\n /**\n * A unique identifier for the query, inside the query tree.\n */\n id: string;\n /**\n * A reference to the query that was augmented\n */\n query: AnyQuery;\n depth: number;\n /**\n * The table that the query is selecting from\n */\n from: AugmentedTable;\n /**\n * The columns that the query is selecting.\n */\n select: Array;\n /**\n * The where clause of the query.\n */\n where: Array;\n children: AugmentedQuery[];\n leftJoin?: {\n joinOp: JoinOp;\n joinTable: AugmentedTable;\n ownColumn: AugmentedColumn;\n otherColumn: AugmentedColumn;\n };\n }\n type WhereOp = WhereBinaryOp | WhereRefOp;\n export type OpValue = {\n type: 'column';\n column: AugmentedColumn;\n } | {\n type: 'value';\n value: any;\n };\n export interface WhereBinaryOp {\n type: 'binary';\n lhs: OpValue;\n op: BinaryOperator;\n rhs: OpValue;\n }\n interface WhereRefOp {\n type: 'ref';\n lhs: AugmentedColumn;\n rhs: AugmentedColumn;\n }\n export interface SelectionColumn {\n type: 'column';\n column: string;\n /**\n * A unique identifier for the column, inside the query result.\n * Example:\n *\n * ```\n * select table.alias.column as id\n * from ...\n * ```\n */\n id: string;\n table: AugmentedTable;\n }\n export function isSelectionColumn(selection: SelectionColumn | SelectionJsonbAgg): selection is SelectionColumn;\n export function isSelectionJsonbAgg(selection: SelectionColumn | SelectionJsonbAgg): selection is SelectionJsonbAgg;\n interface SelectionJsonbAgg {\n type: 'jsonb_agg';\n id: string;\n table: AugmentedTable;\n columns: SelectionColumn[];\n includeColumn: string;\n }\n export interface AugmentedTable {\n alias: string;\n name: string;\n schema: string;\n }\n export interface AugmentedColumn {\n column: string;\n table: AugmentedTable;\n }\n}\ndeclare module \"@synthql/backend/src/cache\" {\n import { Query, QueryResult, Table } from '@synthql/queries';\n export class QueryCache {\n private cache;\n set>(query: Query, result: QueryResult): void;\n get>(query: Query): QueryResult | undefined;\n }\n export function isPlainObject(o: any): o is Object;\n}\ndeclare module \"@synthql/backend/src/escape\" {\n export function escapeColumn(col: string): string;\n}\ndeclare module \"@synthql/backend/src/util/collectFirst\" {\n export function collectFirst(gen: AsyncGenerator): Promise;\n}\ndeclare module \"@synthql/backend/src/types/QueryPlan\" {\n export interface QueryPlan {\n 'Execution Time'?: number;\n 'Planning Time'?: number;\n 'Settings': {};\n 'Triggers': [];\n 'Planning': Planning;\n 'Plan': PlanNode;\n }\n interface Planning {\n 'Local Dirtied Blocks': number;\n 'Local Hit Blocks': number;\n 'Local Read Blocks': number;\n 'Local Written Blocks': number;\n 'Shared Dirtied Blocks': number;\n 'Shared Hit Blocks': number;\n 'Shared Read Blocks': number;\n 'Shared Written Blocks': number;\n 'Temp Read Blocks': number;\n 'Temp Written Blocks': number;\n }\n type PlanNode = PlanLimit | PlanAggregate | PlanNestedLoop | PlanSeqScan | PlanIndexScan;\n interface BasePlan {\n 'Actual Loops': number;\n 'Actual Rows': number;\n 'Actual Startup Time'?: number;\n 'Actual Total Time'?: number;\n 'Local Dirtied Blocks': number;\n 'Local Hit Blocks': number;\n 'Local Read Blocks': number;\n 'Alias'?: string;\n 'Local Written Blocks': number;\n 'Output': string[];\n 'Parallel Aware': boolean;\n 'Plan Rows': number;\n 'Plan Width': number;\n 'Plans'?: PlanNode[];\n 'Shared Dirtied Blocks': number;\n 'Shared Hit Blocks': number;\n 'Shared Read Blocks': number;\n 'Shared Written Blocks': number;\n 'Startup Cost': number;\n 'Total Cost': number;\n 'Temp Read Blocks': number;\n 'Temp Written Blocks': number;\n }\n interface PlanLimit extends BasePlan {\n 'Node Type': 'Limit';\n }\n interface PlanAggregate extends BasePlan {\n 'Node Type': 'Aggregate';\n 'Group Key': string[];\n 'Parent Relationship': 'Outer' | 'Inner';\n 'Partial Mode': 'Simple' | 'Hashed' | 'Mixed';\n 'Strategy': 'Plain' | 'Sorted';\n }\n interface PlanNestedLoop extends BasePlan {\n 'Node Type': 'Nested Loop';\n 'Inner Unique': boolean;\n 'Join Type': 'Left' | 'Inner';\n 'Parent Relationship': 'Outer' | 'Inner';\n 'Shared Dirtied Blocks': number;\n 'Shared Hit Blocks': number;\n 'Shared Read Blocks': number;\n 'Shared Written Blocks': number;\n 'Startup Cost': number;\n 'Total Cost': number;\n 'Temp Read Blocks': number;\n 'Temp Written Blocks': number;\n }\n interface PlanSeqScan extends BasePlan {\n 'Node Type': 'Seq Scan';\n 'Relation Name': string;\n }\n interface PlanIndexScan extends BasePlan {\n 'Node Type': 'Index Scan';\n 'Index Name': string;\n 'Scan Direction': 'Forward' | 'Backward';\n 'Relation Name': string;\n 'Schema': string;\n 'Index Cond'?: string;\n 'Parent Relationship': 'Outer' | 'Inner';\n 'Rows Removed by Index Recheck'?: number;\n }\n}\ndeclare module \"@synthql/backend/src/AugmentedQuery/iterateAugmentedQuery\" {\n import { AugmentedQuery } from \"@synthql/backend/src/types/index\";\n export function iterateAugmentedQuery(query: AugmentedQuery): Generator;\n}\ndeclare module \"@synthql/backend/src/util/isPresent\" {\n export function isPresent(value: T | null | undefined): value is T;\n export function isString(value: unknown): value is string;\n}\ndeclare module \"@synthql/backend/src/AugmentedQuery/augmentQuery\" {\n import { AnyQuery, AugmentedQuery } from \"@synthql/backend/src/types/index\";\n interface AugmentOpts {\n defaultSchema: string;\n depth?: number;\n nodeId?: string;\n includeColumn?: string;\n }\n export function augmentQuery(query: AnyQuery, opts: AugmentOpts): AugmentedQuery;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/composeQuery\" {\n import { Kysely, SelectQueryBuilder } from 'kysely';\n import { AnyQuery, AugmentedQuery } from \"@synthql/backend/src/types/index\";\n export function composeQuery({ defaultSchema, db, query, }: {\n defaultSchema: string;\n db: Kysely;\n query: AnyQuery;\n }): {\n kQuery: SelectQueryBuilder;\n rootQuery: AugmentedQuery;\n };\n}\ndeclare module \"@synthql/backend/src/util/asserts\" {\n export function assertArrayInResult(value: unknown, path: string): Array<{\n [key: string]: any;\n }>;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/applyCardinality\" {\n import { AnyQuery, Cardinality } from \"@synthql/backend/src/types/index\";\n type CardinalityResult = TCardinality extends 'one' ? T : TCardinality extends 'maybe' ? T | null : T[];\n export function applyCardinality(result: Array, cardinality: TCardinality, opts?: {\n query: AnyQuery;\n row: any;\n }): CardinalityResult;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/hydrate\" {\n import { AugmentedQuery } from \"@synthql/backend/src/types/index\";\n interface Row {\n [key: string]: any;\n }\n type AnyQueryResult = undefined | Array | {\n [key: string]: any;\n };\n export function hydrate(data: Array, query: AugmentedQuery): AnyQueryResult;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/QueryEngine\" {\n import { CompiledQuery } from 'kysely';\n import { Pool } from 'pg';\n import { Query, QueryResult, Table } from \"@synthql/queries\";\n import { QueryPlan } from \"@synthql/backend/src/index\";\n export interface QueryProvider> {\n table: TTable;\n execute: (query: TQuery) => Promise>;\n }\n export interface QueryEngineProps {\n url?: string;\n schema?: string;\n providers?: Array>;\n pool?: Pool;\n }\n export class QueryEngine {\n private dialect;\n private db;\n private pool;\n private schema;\n constructor(config: QueryEngineProps);\n execute, TQuery extends Query>(query: TQuery, opts?: {\n schema?: string;\n }): AsyncGenerator>;\n compile(query: T extends Query ? T : never): CompiledQuery;\n explain>(query: Query): Promise;\n private tryToExecute;\n }\n}\ndeclare module \"@synthql/backend/src/index\" {\n export { collectFirst } from \"@synthql/backend/src/util/collectFirst\";\n export type * from \"@synthql/backend/src/types/QueryPlan\";\n export * from \"@synthql/backend/src/AugmentedQuery/iterateAugmentedQuery\";\n export * from \"@synthql/backend/src/QueryEngine/QueryEngine\";\n}\ndeclare module \"@synthql/backend/src/generateSchema\" {\n import { QueryEngine } from \"@synthql/backend/src/index\";\n export interface PgSchema {\n 'information_schema.tables': {\n table_name: string;\n table_schema: string;\n };\n 'information_schema.columns': {\n column_name: string;\n table_name: string;\n table_schema: string;\n data_type: string;\n is_nullable: 'YES' | 'NO';\n udt_name: string;\n udt_schema: string;\n column_default: string | null;\n };\n 'pg_catalog.pg_type': {\n typname: string;\n oid: number;\n };\n 'pg_catalog.pg_enum': {\n enumtypid: number;\n enumlabel: string;\n enumsortorder: number;\n oid: number;\n };\n }\n export type GenerateSchemaConfig = {\n schemas: string[];\n };\n export function generateSchema(queryEngine: QueryEngine, config: GenerateSchemaConfig): Promise<{\n tables: ({\n table_name: string;\n table_schema: string;\n } & {\n columns: ({\n column_name: string;\n data_type: string;\n is_nullable: \"YES\" | \"NO\";\n udt_name: string;\n udt_schema: string;\n } & {})[];\n })[];\n enums: ({\n typname: string;\n } & {\n enumValues: ({\n enumlabel: string;\n } & {})[];\n })[];\n }>;\n}\ndeclare module \"@synthql/backend/src/tests/db\" {\n import type { ColumnType } from 'kysely';\n export type Generated = T extends ColumnType ? ColumnType : ColumnType;\n export type MpaaRating = 'G' | 'NC-17' | 'PG' | 'PG-13' | 'R';\n export type Numeric = ColumnType;\n export type Timestamp = ColumnType;\n export interface Actor {\n actor_id: Generated;\n first_name: string;\n last_name: string;\n last_update: Generated;\n }\n export interface ActorInfo {\n actor_id: number | null;\n film_info: string | null;\n first_name: string | null;\n last_name: string | null;\n }\n export interface Address {\n address: string;\n address_id: Generated;\n address2: string | null;\n city_id: number;\n district: string;\n last_update: Generated;\n phone: string;\n postal_code: string | null;\n }\n export interface Category {\n category_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface City {\n city: string;\n city_id: Generated;\n country_id: number;\n last_update: Generated;\n }\n export interface Country {\n country: string;\n country_id: Generated;\n last_update: Generated;\n }\n export interface Customer {\n active: number | null;\n activebool: Generated;\n address_id: number;\n create_date: Generated;\n customer_id: Generated;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n store_id: number;\n }\n export interface CustomerList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'notes': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Film {\n description: string | null;\n film_id: Generated;\n fulltext: string;\n language_id: number;\n last_update: Generated;\n length: number | null;\n original_language_id: number | null;\n rating: Generated;\n release_year: number | null;\n rental_duration: Generated;\n rental_rate: Generated;\n replacement_cost: Generated;\n special_features: string[] | null;\n title: string;\n }\n export interface FilmActor {\n actor_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmCategory {\n category_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface Inventory {\n film_id: number;\n inventory_id: Generated;\n last_update: Generated;\n store_id: number;\n }\n export interface Language {\n language_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface NicerButSlowerFilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface PaymentP202201 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202202 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202203 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202204 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202205 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202206 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202207 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface Rental {\n customer_id: number;\n inventory_id: number;\n last_update: Generated;\n rental_date: Timestamp;\n rental_id: Generated;\n return_date: Timestamp | null;\n staff_id: number;\n }\n export interface SalesByFilmCategory {\n category: string | null;\n total_sales: Numeric | null;\n }\n export interface SalesByStore {\n manager: string | null;\n store: string | null;\n total_sales: Numeric | null;\n }\n export interface Staff {\n active: Generated;\n address_id: number;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n password: string | null;\n picture: Buffer | null;\n staff_id: Generated;\n store_id: number;\n username: string;\n }\n export interface StaffList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Store {\n address_id: number;\n last_update: Generated;\n manager_staff_id: number;\n store_id: Generated;\n }\n export interface DB {\n actor: Actor;\n actor_info: ActorInfo;\n address: Address;\n category: Category;\n city: City;\n country: Country;\n customer: Customer;\n customer_list: CustomerList;\n film: Film;\n film_actor: FilmActor;\n film_category: FilmCategory;\n film_list: FilmList;\n inventory: Inventory;\n language: Language;\n nicer_but_slower_film_list: NicerButSlowerFilmList;\n payment_p2022_01: PaymentP202201;\n payment_p2022_02: PaymentP202202;\n payment_p2022_03: PaymentP202203;\n payment_p2022_04: PaymentP202204;\n payment_p2022_05: PaymentP202205;\n payment_p2022_06: PaymentP202206;\n payment_p2022_07: PaymentP202207;\n rental: Rental;\n sales_by_film_category: SalesByFilmCategory;\n sales_by_store: SalesByStore;\n staff: Staff;\n staff_list: StaffList;\n store: Store;\n }\n}\ndeclare module \"@synthql/backend/src/tests/queryEngine\" {\n import { QueryEngine } from \"@synthql/backend/src/QueryEngine/QueryEngine\";\n import { DB } from \"@synthql/backend/src/tests/db\";\n export const queryEngine: QueryEngine;\n}\ndeclare module \"@synthql/backend/src/generateSchema.test\" { }\ndeclare module \"@synthql/backend/src/tests/postgres\" {\n import pg from 'postgres';\n export const sql: pg.Sql<{}>;\n}\ndeclare module \"@synthql/backend/src/tests/queries\" {\n import { Table, WhereClause } from '@synthql/queries';\n import { DB } from \"@synthql/backend/src/tests/db\";\n export function from>(table: TTable): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function actor(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function findActorById(actorId: number): {\n from: \"actor\";\n where: {\n actor_id: number;\n };\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n export function findActors(): {\n from: \"actor\";\n where: {};\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n export function language(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function findLanguageById(id: WhereClause): import(\"@synthql/queries/src/query\").QueryBuilder;\n }, \"many\", {}, {\n language_id: true;\n name: true;\n last_update: true;\n }, undefined, [\"language_id\"]>;\n export function movie(): import(\"@synthql/queries/src/query\").QueryBuilder;\n };\n select: {\n language_id: true;\n name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"language_id\"];\n };\n film_actor: {\n from: \"film_actor\";\n where: {\n film_id: import(\"@synthql/queries\").RefOp;\n };\n select: {};\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"id\"];\n };\n actors: {\n from: \"actor\";\n where: {\n actor_id: import(\"@synthql/queries\").RefOp;\n };\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n }, {\n title: true;\n description: true;\n release_year: true;\n }, undefined, [\"film_id\"]>;\n export function country(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function city(): import(\"@synthql/queries/src/query\").QueryBuilder;\n };\n select: {\n country_id: true;\n country: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"country_id\"];\n };\n }, {\n city_id: true;\n city: true;\n last_update: true;\n country_id: true;\n }, undefined, [\"city_id\"]>;\n export function findCityById(id: WhereClause): {\n from: \"city\";\n where: {\n city_id: WhereClause;\n };\n select: {\n city_id: true;\n city: true;\n last_update: true;\n country_id: true;\n };\n include: {\n country: {\n from: \"country\";\n where: {\n country_id: WhereClause;\n };\n select: {\n country_id: true;\n country: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"country_id\"];\n };\n };\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: undefined;\n groupingId: [\"city_id\"];\n };\n}\ndeclare module \"@synthql/backend/src/tests/select.test\" { }\ndeclare module \"@synthql/backend/src/util/collectAsync\" {\n export function collectAsync(gen: AsyncGenerator): Promise;\n}\n/**\n * Performs a LEFT JOIN on two arrays using a hash table.\n */\ndeclare function hashLeftJoin(left: TLeft[], right: TRight[], leftKey: (l: TLeft) => string, rightKey: (r: TRight) => string): Array<[TLeft, TRight | undefined]>;\n\n\n declare module \"@synthql/backend\" { export * from \"@synthql/backend/src/index\"; }", "fileName": "@synthql/backend/index.d.ts" }, { "module": "queries", - "types": "/// \ndeclare module \"@synthql/queries/src/types/types\" {\n import type { BinaryOperator } from 'kysely';\n /**\n * The name of a table in the database.\n */\n export type Table = keyof DB & string;\n /**\n * The name of a column in the database.\n *\n * @param TTable The table the column belongs to.\n */\n export type Column> = keyof DB[TTable] & string;\n export type ColumnReference = {\n [TTable in keyof DB]: DB[TTable] extends object ? `${TTable & string}.${(keyof DB[TTable] & string) | '*'}` : never;\n }[keyof DB];\n /**\n * The value of a column in the database.\n *\n * Our schemas are not null-strict, so every column can be null.\n *\n * @param TTable The table the column belongs to.\n * @param TColumn The column the value belongs to.\n */\n export type ColumnValue, TColumn extends Column> = DB[TTable][TColumn] extends Selectable ? T : DB[TTable][TColumn] extends Selectable | null ? T | null : DB[TTable][TColumn];\n type Selectable = {\n readonly __select__: T;\n };\n /**\n * A binary operator.\n */\n type BinaryOp, TColumn extends Column> = {\n [op in BinaryOperator]?: ColumnValue | Array> | RefOp;\n };\n export type JoinOp = '=' | '= any';\n export type RefOp = {\n $ref: {\n table: Table;\n column: string;\n op?: JoinOp;\n };\n };\n export function isRefOp(op: any): op is RefOp;\n export type WhereClause, TColumn extends Column> = ColumnValue | BinaryOp | RefOp;\n export type Where> = {\n [TColumn in Column]?: WhereClause;\n };\n export type Select> = {\n [TColumn in Column]?: true;\n };\n export type Include = {\n [k in string]: Query> extends Query ? Query : never;\n };\n export type Query> = {\n from: TTable;\n where: Where;\n select: Select;\n include?: Include;\n limit?: number;\n cardinality?: 'one' | 'maybe' | 'many';\n lazy?: true;\n groupingId?: string[];\n };\n}\ndeclare module \"@synthql/queries/src/ref\" {\n import { Column, ColumnReference, RefOp, Table } from \"@synthql/queries/src/types/types\";\n export function col(ref: ColumnReference): RefOp;\n export function ref(): {\n table: >(table: TTable) => {\n column: >(column: TColumn) => RefOp;\n eqAny: >(column: TColumn_1) => RefOp;\n };\n };\n}\ndeclare module \"@synthql/queries/src/types/QueryResult\" {\n import { Column, ColumnValue, Query, Table } from \"@synthql/queries/src/types/types\";\n export type QueryResult = TQuery extends Query ? ApplyCardinality : never;\n type QueryResultInner, TQuery extends Query> = QueryResultFromSelect & QueryResultFromInclude;\n type QueryResultFromSelect, TQuery extends Query> = {\n [TCol in SelectedColumns]: ColumnValue;\n };\n type SelectedColumns, TQuery extends Query> = TQuery['select'] extends true ? Column : // Select only the specified columns\n Column & keyof TQuery['select'];\n type IncludedColumns, TQuery extends Query> = keyof TQuery['include'];\n type QueryResultFromInclude, TQuery extends Query> = {\n [TCol in IncludedColumns]: QueryResult;\n };\n type LazyQueryResult, TQuery extends Query> = {\n status: 'pending';\n } | {\n status: 'done';\n data: QueryResult;\n } | {\n status: 'error';\n error: any;\n };\n type MaybeQueryResult, TQuery extends Query> = null | QueryResultInner;\n type ManyQueryResult, TQuery extends Query> = QueryResultInner[];\n type ApplyCardinality, TQuery extends Query> = TQuery extends {\n lazy: true;\n } ? LazyQueryResult : TQuery extends {\n cardinality: 'many';\n } ? ManyQueryResult : TQuery extends {\n cardinality: 'one';\n } ? QueryResultInner : TQuery extends {\n cardinality: 'maybe';\n } ? MaybeQueryResult : never;\n}\ndeclare module \"@synthql/queries/src/query\" {\n import { Column, Include, Select, Table, Where } from \"@synthql/queries/src/types/types\";\n export class QueryBuilder, TWhere extends Where, TCardinality extends 'one' | 'maybe' | 'many', TInclude extends Include, TSelect extends Select, TLazy extends true | undefined, TGroupingId extends string[]> {\n private _from;\n private _where;\n private _select;\n private _include;\n private _limit;\n private _cardinality;\n private _lazy;\n private _groupingId;\n constructor(_from: TTable, _where: TWhere, _select: TSelect, _include: TInclude, _limit: number | undefined, _cardinality: TCardinality, _lazy: TLazy, _groupingId: TGroupingId);\n private build;\n /**\n * Sets the limit of the query.\n */\n limit(limit: number): QueryBuilder;\n /**\n * Builds a query that returns exactly one row. Will throw an error if the query returns 0.\n *\n * Also sets the limit to 1.\n */\n one(): {\n from: TTable;\n where: TWhere;\n select: TSelect;\n include: TInclude;\n limit: number | undefined;\n cardinality: \"one\";\n lazy: TLazy;\n groupingId: TGroupingId;\n };\n /**\n * Builds a query that returns many rows.\n */\n many(): {\n from: TTable;\n where: TWhere;\n select: TSelect;\n include: TInclude;\n limit: number | undefined;\n cardinality: \"many\";\n lazy: TLazy;\n groupingId: TGroupingId;\n };\n /**\n * Builds a query with a cardinality of 'maybe'. This means that the query will return 0 or 1 rows.\n */\n maybe(): {\n from: TTable;\n where: TWhere;\n select: TSelect;\n include: TInclude;\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: TLazy;\n groupingId: TGroupingId;\n };\n select>(select: TSelect): QueryBuilder;\n /**\n * Select specific columns from the table. `columns` is a shorthand for `select`. Example:\n *\n * ```ts\n * const q = from('actor')\n * .columns('actor_id', 'last_name')\n * .many()\n *\n * // is equivalent to\n * const q = from('actor')\n * .select({\n * actor_id: true,\n * last_name: true,\n * })\n * ```\n */\n columns>>(...keys: TKeys): QueryBuilder;\n include>(include: TInclude): QueryBuilder;\n alsoInclude>(include: TNewInclude): QueryBuilder;\n where>(where: TWhere): QueryBuilder;\n lazy(): QueryBuilder;\n groupingId(...id: TGroupingId): QueryBuilder;\n }\n export function query(): {\n from>(table: TTable): QueryBuilder;\n };\n}\ndeclare module \"@synthql/queries/src/index\" {\n export { col, ref } from \"@synthql/queries/src/ref\";\n export * from \"@synthql/queries/src/types/types\";\n export * from \"@synthql/queries/src/types/QueryResult\";\n export { query } from \"@synthql/queries/src/query\";\n}\ndeclare module \"@synthql/queries/src/expression/Expression\" {\n export type Primitive = string | number | boolean | null | Date;\n export const unaryOperators: readonly [\"not\", \"-\", \"exists\", \"not exists\"];\n export type UnaryOperator = (typeof unaryOperators)[number];\n export const binaryOperators: readonly [\"=\", \"==\", \"!=\", \"<>\", \">\", \">=\", \"<\", \"<=\", \"in\", \"not in\", \"is\", \"is not\", \"like\", \"not like\", \"match\", \"ilike\", \"not ilike\", \"@>\", \"<@\", \"&&\", \"?\", \"?&\", \"!<\", \"!>\", \"<=>\", \"!~\", \"~\", \"~*\", \"!~*\", \"@@\", \"@@@\", \"!!\", \"<->\", \"regexp\", \"+\", \"-\", \"*\", \"/\", \"%\", \"^\", \"&\", \"|\", \"#\", \"<<\", \">>\", \"&&\", \"||\"];\n export type BinaryOperator = (typeof binaryOperators)[number];\n export const nAryOperators: readonly [\"and\", \"or\", \"=\", \"==\", \"!=\", \"<>\", \">\", \">=\", \"<\", \"<=\", \"in\", \"not in\", \"is\", \"is not\", \"like\", \"#>\", \"#>>\", \"not like\", \"match\", \"ilike\", \"not ilike\", \"@>\", \"<@\", \"&&\", \"?\", \"?&\", \"!<\", \"!>\", \"<=>\", \"!~\", \"~\", \"~*\", \"!~*\", \"@@\", \"@@@\", \"!!\", \"<->\", \"regexp\", \"+\", \"-\", \"*\", \"/\", \"%\", \"^\", \"&\", \"|\", \"#\", \"<<\", \">>\", \"&&\", \"||\", \"->\", \"->>\", \"not\", \"-\", \"exists\", \"not exists\", \"between\", \"between symmetric\"];\n export type NAryOperator = (typeof nAryOperators)[number];\n /**\n * An expression that invokes a function\n */\n export type ExpFunctionInvocation = ['>invoke', functionName: string, ...Exp[]];\n /**\n * An expression that references a column in a table\n */\n export type ExpColumnReference = Context;\n /**\n * An expression that casts an expression to a different type\n */\n export type ExpCast = ['>::', exp: Exp, type: string];\n /**\n * An expression that conditionally evaluates to one of two expressions\n */\n export type ExpWhen = ['>when', condition: Exp, whenTrue: Exp, whenFalse: Exp];\n /**\n * A literal is serialized as a value in the query\n * e.g. `SELECT * FROM table WHERE column = 1`\n */\n export type ExpLiteral = ['>literal', Primitive] | Exclude;\n /**\n * A parameter is serialized as a placeholder in the query\n * e.g. `SELECT * FROM table WHERE column = $1`\n */\n export type ExpParam = ['>param', Primitive];\n export type Exp = ExpLiteral | ExpParam | ExpFunctionInvocation | ExpColumnReference | ExpCast | ExpWhen | [UnaryOperator, Exp] | [BinaryOperator, Exp, Exp] | [NAryOperator, Exp, ...Exp[]];\n}\ndeclare module \"@synthql/queries/src/test/pagila.db\" {\n import type { ColumnType } from 'kysely';\n import { Table } from \"@synthql/queries/src/index\";\n import { Exp } from \"@synthql/queries/src/expression/Expression\";\n export type Generated = T extends ColumnType ? ColumnType : ColumnType;\n export type MpaaRating = 'G' | 'NC-17' | 'PG' | 'PG-13' | 'R';\n export type Numeric = ColumnType;\n export type Timestamp = ColumnType;\n export interface Actor {\n actor_id: Generated;\n first_name: string;\n last_name: string;\n last_update: Generated;\n }\n export interface ActorInfo {\n actor_id: number | null;\n film_info: string | null;\n first_name: string | null;\n last_name: string | null;\n }\n export interface Address {\n address: string;\n address_id: Generated;\n address2: string | null;\n city_id: number;\n district: string;\n last_update: Generated;\n phone: string;\n postal_code: string | null;\n }\n export interface Category {\n category_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface City {\n city: string;\n city_id: Generated;\n country_id: number;\n last_update: Generated;\n }\n export interface Country {\n country: string;\n country_id: Generated;\n last_update: Generated;\n }\n export interface Customer {\n active: number | null;\n activebool: Generated;\n address_id: number;\n create_date: Generated;\n customer_id: Generated;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n store_id: number;\n }\n export interface CustomerList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'notes': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Film {\n description: string | null;\n film_id: Generated;\n fulltext: string;\n language_id: number;\n last_update: Generated;\n length: number | null;\n original_language_id: number | null;\n rating: Generated;\n release_year: number | null;\n rental_duration: Generated;\n rental_rate: Generated;\n replacement_cost: Generated;\n special_features: string[] | null;\n title: string;\n }\n export interface FilmActor {\n actor_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmCategory {\n category_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface Inventory {\n film_id: number;\n inventory_id: Generated;\n last_update: Generated;\n store_id: number;\n }\n export interface Language {\n language_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface NicerButSlowerFilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface PaymentP202201 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202202 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202203 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202204 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202205 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202206 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202207 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface Rental {\n customer_id: number;\n inventory_id: number;\n last_update: Generated;\n rental_date: Timestamp;\n rental_id: Generated;\n return_date: Timestamp | null;\n staff_id: number;\n }\n export interface SalesByFilmCategory {\n category: string | null;\n total_sales: Numeric | null;\n }\n export interface SalesByStore {\n manager: string | null;\n store: string | null;\n total_sales: Numeric | null;\n }\n export interface Staff {\n active: Generated;\n address_id: number;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n password: string | null;\n picture: Buffer | null;\n staff_id: Generated;\n store_id: number;\n username: string;\n }\n export interface StaffList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Store {\n address_id: number;\n last_update: Generated;\n manager_staff_id: number;\n store_id: Generated;\n }\n export interface DB {\n actor: Actor;\n actor_info: ActorInfo;\n address: Address;\n category: Category;\n city: City;\n country: Country;\n customer: Customer;\n customer_list: CustomerList;\n film: Film;\n film_actor: FilmActor;\n film_category: FilmCategory;\n film_list: FilmList;\n inventory: Inventory;\n language: Language;\n nicer_but_slower_film_list: NicerButSlowerFilmList;\n payment_p2022_01: PaymentP202201;\n payment_p2022_02: PaymentP202202;\n payment_p2022_03: PaymentP202203;\n payment_p2022_04: PaymentP202204;\n payment_p2022_05: PaymentP202205;\n payment_p2022_06: PaymentP202206;\n payment_p2022_07: PaymentP202207;\n rental: Rental;\n sales_by_film_category: SalesByFilmCategory;\n sales_by_store: SalesByStore;\n staff: Staff;\n staff_list: StaffList;\n store: Store;\n }\n export const from: >(table: TTable) => import(\"@synthql/queries/src/query\").QueryBuilder;\n export function exp(exp: Exp): Exp;\n}\ndeclare module \"@synthql/queries/src/query.test\" { }\ndeclare module \"@synthql/queries/src/expression/dsl\" {\n import { Exp, Primitive } from \"@synthql/queries/src/expression/Expression\";\n export function equals(exp1: Exp, exp2: Exp): Exp;\n export function isPositive(exp: Exp): Exp;\n export function isNegative(exp: Exp): Exp;\n export function isZero(exp: Exp): Exp;\n export function coalesce(exp: Exp, def: Exp): Exp;\n export function isNotNull(exp: Exp): Exp;\n export function isNull(exp: Exp): Exp;\n export function sum(exp: Exp): Exp;\n export function param(param: TParam): Exp;\n export function literal(param: TParam): Exp;\n export function when(condition: Exp, whenTrue: Exp, whenFalse: Exp): Exp;\n export const cast: {\n asText: (exp: Exp) => Exp;\n asNumeric: (exp: Exp) => Exp;\n asInteger: (exp: Exp) => Exp;\n asUuid: (exp: Exp) => Exp;\n };\n export const json: {\n get: (exp: Exp, key: string) => Exp;\n getAsText: (exp: Exp, key: string) => Exp;\n getAsNumeric: (exp: Exp, key: string) => Exp;\n agg: (exp: Exp) => Exp;\n buildObject: (...exp: Exp[]) => Exp;\n };\n export function distinct(exp: Exp): Exp;\n export function count(exp: Exp): Exp;\n export const jsonb: {\n buildObject: (...exp: Exp[]) => Exp;\n agg: (exp: Exp) => Exp;\n };\n export function chain(exp: Exp, ...fns: Array<((exp: Exp) => Exp)>): Exp;\n}\ndeclare module \"@synthql/queries/src/util/isString\" {\n export function isString(x: unknown): x is string;\n}\n\n declare module \"@synthql/queries\" { export * from \"@synthql/queries/src/index\"; }", + "types": "/// \ndeclare module \"@synthql/queries/src/types/types\" {\n import type { BinaryOperator } from 'kysely';\n /**\n * The name of a table in the database.\n */\n export type Table = keyof DB & string;\n /**\n * The name of a column in the database.\n *\n * @param TTable The table the column belongs to.\n */\n export type Column> = keyof DB[TTable] & string;\n export type ColumnReference = {\n [TTable in keyof DB]: DB[TTable] extends object ? `${TTable & string}.${(keyof DB[TTable] & string) | '*'}` : never;\n }[keyof DB];\n /**\n * The value of a column in the database.\n *\n * Our schemas are not null-strict, so every column can be null.\n *\n * @param TTable The table the column belongs to.\n * @param TColumn The column the value belongs to.\n */\n export type ColumnValue, TColumn extends Column> = DB[TTable][TColumn] extends Selectable ? T : DB[TTable][TColumn] extends Selectable | null ? T | null : DB[TTable][TColumn];\n type Selectable = {\n readonly __select__: T;\n };\n /**\n * A binary operator.\n */\n type BinaryOp, TColumn extends Column> = {\n [op in BinaryOperator]?: ColumnValue | Array> | RefOp;\n };\n export type JoinOp = '=' | '= any';\n export type RefOp = {\n $ref: {\n table: Table;\n column: string;\n op?: JoinOp;\n };\n };\n export function isRefOp(op: any): op is RefOp;\n export type WhereClause, TColumn extends Column> = ColumnValue | BinaryOp | RefOp;\n export type Where> = {\n [TColumn in Column]?: WhereClause;\n };\n export type Select> = {\n [TColumn in Column]?: true;\n };\n export type Include = {\n [k in string]: Query> extends Query ? Query : never;\n };\n export type Query> = {\n from: TTable;\n where: Where;\n select: Select;\n include?: Include;\n limit?: number;\n cardinality?: 'one' | 'maybe' | 'many';\n lazy?: true;\n groupingId?: string[];\n };\n}\ndeclare module \"@synthql/queries/src/ref\" {\n import { Column, ColumnReference, RefOp, Table } from \"@synthql/queries/src/types/types\";\n export function col(ref: ColumnReference): RefOp;\n export function ref(): {\n table: >(table: TTable) => {\n column: >(column: TColumn) => RefOp;\n eqAny: >(column: TColumn_1) => RefOp;\n };\n };\n}\ndeclare module \"@synthql/queries/src/types/QueryResult\" {\n import { Column, ColumnValue, Query, Table } from \"@synthql/queries/src/types/types\";\n export type QueryResult = TQuery extends Query ? ApplyCardinality : never;\n type QueryResultInner, TQuery extends Query> = QueryResultFromSelect & QueryResultFromInclude;\n type QueryResultFromSelect, TQuery extends Query> = {\n [TCol in SelectedColumns]: ColumnValue;\n };\n type SelectedColumns, TQuery extends Query> = TQuery['select'] extends true ? Column : // Select only the specified columns\n Column & keyof TQuery['select'];\n type IncludedColumns, TQuery extends Query> = keyof TQuery['include'];\n type QueryResultFromInclude, TQuery extends Query> = {\n [TCol in IncludedColumns]: QueryResult;\n };\n type LazyQueryResult, TQuery extends Query> = {\n status: 'pending';\n } | {\n status: 'done';\n data: QueryResult;\n } | {\n status: 'error';\n error: any;\n };\n type MaybeQueryResult, TQuery extends Query> = null | QueryResultInner;\n type ManyQueryResult, TQuery extends Query> = QueryResultInner[];\n type ApplyCardinality, TQuery extends Query> = TQuery extends {\n lazy: true;\n } ? LazyQueryResult : TQuery extends {\n cardinality: 'many';\n } ? ManyQueryResult : TQuery extends {\n cardinality: 'one';\n } ? QueryResultInner : TQuery extends {\n cardinality: 'maybe';\n } ? MaybeQueryResult : never;\n}\ndeclare module \"@synthql/queries/src/query\" {\n import { Column, Include, Select, Table, Where } from \"@synthql/queries/src/types/types\";\n export class QueryBuilder, TWhere extends Where, TCardinality extends 'one' | 'maybe' | 'many', TInclude extends Include, TSelect extends Select, TLazy extends true | undefined, TGroupingId extends string[]> {\n private _from;\n private _where;\n private _select;\n private _include;\n private _limit;\n private _cardinality;\n private _lazy;\n private _groupingId;\n constructor(_from: TTable, _where: TWhere, _select: TSelect, _include: TInclude, _limit: number | undefined, _cardinality: TCardinality, _lazy: TLazy, _groupingId: TGroupingId);\n private build;\n /**\n * Sets the limit of the query.\n */\n limit(limit: number): QueryBuilder;\n /**\n * Builds a query that returns exactly one row. Will throw an error if the query returns 0.\n *\n * Also sets the limit to 1.\n */\n one(): {\n from: TTable;\n where: TWhere;\n select: TSelect;\n include: TInclude;\n limit: number | undefined;\n cardinality: \"one\";\n lazy: TLazy;\n groupingId: TGroupingId;\n };\n /**\n * Builds a query that returns many rows.\n */\n many(): {\n from: TTable;\n where: TWhere;\n select: TSelect;\n include: TInclude;\n limit: number | undefined;\n cardinality: \"many\";\n lazy: TLazy;\n groupingId: TGroupingId;\n };\n /**\n * Builds a query with a cardinality of 'maybe'. This means that the query will return 0 or 1 rows.\n */\n maybe(): {\n from: TTable;\n where: TWhere;\n select: TSelect;\n include: TInclude;\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: TLazy;\n groupingId: TGroupingId;\n };\n select>(select: TSelect): QueryBuilder;\n /**\n * Select specific columns from the table. `columns` is a shorthand for `select`. Example:\n *\n * ```ts\n * const q = from('actor')\n * .columns('actor_id', 'last_name')\n * .many()\n *\n * // is equivalent to\n * const q = from('actor')\n * .select({\n * actor_id: true,\n * last_name: true,\n * })\n * ```\n */\n columns>>(...keys: TKeys): QueryBuilder;\n include>(include: TInclude): QueryBuilder;\n alsoInclude>(include: TNewInclude): QueryBuilder;\n where>(where: TWhere): QueryBuilder;\n lazy(): QueryBuilder;\n groupingId(...id: TGroupingId): QueryBuilder;\n }\n export function query(): {\n from>(table: TTable): QueryBuilder;\n };\n}\ndeclare module \"@synthql/queries/src/index\" {\n export { col, ref } from \"@synthql/queries/src/ref\";\n export * from \"@synthql/queries/src/types/types\";\n export * from \"@synthql/queries/src/types/QueryResult\";\n export { query } from \"@synthql/queries/src/query\";\n}\ndeclare module \"@synthql/queries/src/expression/Expression\" {\n export type Primitive = string | number | boolean | null | Date;\n export const unaryOperators: readonly [\"not\", \"-\", \"exists\", \"not exists\"];\n export type UnaryOperator = (typeof unaryOperators)[number];\n export const binaryOperators: readonly [\"=\", \"==\", \"!=\", \"<>\", \">\", \">=\", \"<\", \"<=\", \"in\", \"not in\", \"is\", \"is not\", \"like\", \"not like\", \"match\", \"ilike\", \"not ilike\", \"@>\", \"<@\", \"&&\", \"?\", \"?&\", \"!<\", \"!>\", \"<=>\", \"!~\", \"~\", \"~*\", \"!~*\", \"@@\", \"@@@\", \"!!\", \"<->\", \"regexp\", \"+\", \"-\", \"*\", \"/\", \"%\", \"^\", \"&\", \"|\", \"#\", \"<<\", \">>\", \"&&\", \"||\"];\n export type BinaryOperator = (typeof binaryOperators)[number];\n export const nAryOperators: readonly [\"and\", \"or\", \"=\", \"==\", \"!=\", \"<>\", \">\", \">=\", \"<\", \"<=\", \"in\", \"not in\", \"is\", \"is not\", \"like\", \"#>\", \"#>>\", \"not like\", \"match\", \"ilike\", \"not ilike\", \"@>\", \"<@\", \"&&\", \"?\", \"?&\", \"!<\", \"!>\", \"<=>\", \"!~\", \"~\", \"~*\", \"!~*\", \"@@\", \"@@@\", \"!!\", \"<->\", \"regexp\", \"+\", \"-\", \"*\", \"/\", \"%\", \"^\", \"&\", \"|\", \"#\", \"<<\", \">>\", \"&&\", \"||\", \"->\", \"->>\", \"not\", \"-\", \"exists\", \"not exists\", \"between\", \"between symmetric\"];\n export type NAryOperator = (typeof nAryOperators)[number];\n /**\n * An expression that invokes a function\n */\n export type ExpFunctionInvocation = ['>invoke', functionName: string, ...Exp[]];\n /**\n * An expression that references a column in a table\n */\n export type ExpColumnReference = Context;\n /**\n * An expression that casts an expression to a different type\n */\n export type ExpCast = ['>::', exp: Exp, type: string];\n /**\n * An expression that conditionally evaluates to one of two expressions\n */\n export type ExpWhen = ['>when', condition: Exp, whenTrue: Exp, whenFalse: Exp];\n /**\n * A literal is serialized as a value in the query\n * e.g. `SELECT * FROM table WHERE column = 1`\n */\n export type ExpLiteral = ['>literal', Primitive] | Exclude;\n /**\n * A parameter is serialized as a placeholder in the query\n * e.g. `SELECT * FROM table WHERE column = $1`\n */\n export type ExpParam = ['>param', Primitive];\n export type Exp = ExpLiteral | ExpParam | ExpFunctionInvocation | ExpColumnReference | ExpCast | ExpWhen | [UnaryOperator, Exp] | [BinaryOperator, Exp, Exp] | [NAryOperator, Exp, ...Exp[]];\n}\ndeclare module \"@synthql/queries/src/test/pagila.db\" {\n import type { ColumnType } from 'kysely';\n import { Table } from \"@synthql/queries/src/index\";\n import { Exp } from \"@synthql/queries/src/expression/Expression\";\n export type Generated = T extends ColumnType ? ColumnType : ColumnType;\n export type MpaaRating = 'G' | 'NC-17' | 'PG' | 'PG-13' | 'R';\n export type Numeric = ColumnType;\n export type Timestamp = ColumnType;\n export interface Actor {\n actor_id: Generated;\n first_name: string;\n last_name: string;\n last_update: Generated;\n }\n export interface ActorInfo {\n actor_id: number | null;\n film_info: string | null;\n first_name: string | null;\n last_name: string | null;\n }\n export interface Address {\n address: string;\n address_id: Generated;\n address2: string | null;\n city_id: number;\n district: string;\n last_update: Generated;\n phone: string;\n postal_code: string | null;\n }\n export interface Category {\n category_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface City {\n city: string;\n city_id: Generated;\n country_id: number;\n last_update: Generated;\n }\n export interface Country {\n country: string;\n country_id: Generated;\n last_update: Generated;\n }\n export interface Customer {\n active: number | null;\n activebool: Generated;\n address_id: number;\n create_date: Generated;\n customer_id: Generated;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n store_id: number;\n }\n export interface CustomerList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'notes': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Film {\n description: string | null;\n film_id: Generated;\n fulltext: string;\n language_id: number;\n last_update: Generated;\n length: number | null;\n original_language_id: number | null;\n rating: Generated;\n release_year: number | null;\n rental_duration: Generated;\n rental_rate: Generated;\n replacement_cost: Generated;\n special_features: string[] | null;\n title: string;\n }\n export interface FilmActor {\n actor_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmCategory {\n category_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface Inventory {\n film_id: number;\n inventory_id: Generated;\n last_update: Generated;\n store_id: number;\n }\n export interface Language {\n language_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface NicerButSlowerFilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface PaymentP202201 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202202 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202203 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202204 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202205 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202206 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202207 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface Rental {\n customer_id: number;\n inventory_id: number;\n last_update: Generated;\n rental_date: Timestamp;\n rental_id: Generated;\n return_date: Timestamp | null;\n staff_id: number;\n }\n export interface SalesByFilmCategory {\n category: string | null;\n total_sales: Numeric | null;\n }\n export interface SalesByStore {\n manager: string | null;\n store: string | null;\n total_sales: Numeric | null;\n }\n export interface Staff {\n active: Generated;\n address_id: number;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n password: string | null;\n picture: Buffer | null;\n staff_id: Generated;\n store_id: number;\n username: string;\n }\n export interface StaffList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Store {\n address_id: number;\n last_update: Generated;\n manager_staff_id: number;\n store_id: Generated;\n }\n export interface DB {\n actor: Actor;\n actor_info: ActorInfo;\n address: Address;\n category: Category;\n city: City;\n country: Country;\n customer: Customer;\n customer_list: CustomerList;\n film: Film;\n film_actor: FilmActor;\n film_category: FilmCategory;\n film_list: FilmList;\n inventory: Inventory;\n language: Language;\n nicer_but_slower_film_list: NicerButSlowerFilmList;\n payment_p2022_01: PaymentP202201;\n payment_p2022_02: PaymentP202202;\n payment_p2022_03: PaymentP202203;\n payment_p2022_04: PaymentP202204;\n payment_p2022_05: PaymentP202205;\n payment_p2022_06: PaymentP202206;\n payment_p2022_07: PaymentP202207;\n rental: Rental;\n sales_by_film_category: SalesByFilmCategory;\n sales_by_store: SalesByStore;\n staff: Staff;\n staff_list: StaffList;\n store: Store;\n }\n export const from: >(table: TTable) => import(\"@synthql/queries/src/query\").QueryBuilder;\n export function exp(exp: Exp): Exp;\n}\ndeclare module \"@synthql/queries/src/query.test\" { }\ndeclare module \"@synthql/queries/src/expression/dsl\" {\n import { Exp, Primitive } from \"@synthql/queries/src/expression/Expression\";\n export function equals(exp1: Exp, exp2: Exp): Exp;\n export function isPositive(exp: Exp): Exp;\n export function isNegative(exp: Exp): Exp;\n export function isZero(exp: Exp): Exp;\n export function coalesce(exp: Exp, def: Exp): Exp;\n export function isNotNull(exp: Exp): Exp;\n export function isNull(exp: Exp): Exp;\n export function sum(exp: Exp): Exp;\n export function param(param: TParam): Exp;\n export function literal(param: TParam): Exp;\n export function when(condition: Exp, whenTrue: Exp, whenFalse: Exp): Exp;\n export const cast: {\n asText: (exp: Exp) => Exp;\n asNumeric: (exp: Exp) => Exp;\n asInteger: (exp: Exp) => Exp;\n asUuid: (exp: Exp) => Exp;\n };\n export const json: {\n get: (exp: Exp, key: string) => Exp;\n getAsText: (exp: Exp, key: string) => Exp;\n getAsNumeric: (exp: Exp, key: string) => Exp;\n agg: (exp: Exp) => Exp;\n buildObject: (...exp: Exp[]) => Exp;\n };\n export function distinct(exp: Exp): Exp;\n export function count(exp: Exp): Exp;\n export const jsonb: {\n buildObject: (...exp: Exp[]) => Exp;\n agg: (exp: Exp) => Exp;\n };\n export function chain(exp: Exp, ...fns: Array<((exp: Exp) => Exp)>): Exp;\n}\ndeclare module \"@synthql/queries/src/util/isString\" {\n export function isString(x: unknown): x is string;\n}\n\n declare module \"@synthql/queries\" { export * from \"@synthql/queries/src/index\"; }", "fileName": "@synthql/queries/index.d.ts" } ] From 283c43d7fb0f30ef63605ed657ae9cfa6e0d8e5d Mon Sep 17 00:00:00 2001 From: Fernando Hurtado Date: Fri, 27 Sep 2024 21:10:16 +0200 Subject: [PATCH 3/7] wip --- .../src/execution/planning/createPlanningQuery.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/execution/planning/createPlanningQuery.test.ts b/packages/backend/src/execution/planning/createPlanningQuery.test.ts index 0e69f263..c919c271 100644 --- a/packages/backend/src/execution/planning/createPlanningQuery.test.ts +++ b/packages/backend/src/execution/planning/createPlanningQuery.test.ts @@ -1,10 +1,10 @@ -import { describe, expect, test } from 'vitest'; import { col } from '@synthql/queries'; +import { describe, expect, test } from 'vitest'; +import { from } from '../../tests/generated'; import { store } from '../../tests/queries.v2'; -import { createPlanningQuery } from './createPlanningQuery'; -import { PlanningQuery } from '../types'; import { printPath } from '../../util/path/printPath'; -import { from } from '../../tests/generated'; +import { PlanningQuery } from '../types'; +import { createPlanningQuery } from './createPlanningQuery'; describe('createPlanningQuery', () => { function simplifyQuery(q: PlanningQuery): { @@ -144,7 +144,7 @@ describe('createPlanningQuery', () => { .one(); const query = from('store') - .select({ store_id: true }) + .columns('store_id') .include({ address, }) From a6ce6412776603a023b8237cdcc38f616d39fe10 Mon Sep 17 00:00:00 2001 From: Fernando Hurtado Date: Mon, 30 Sep 2024 13:16:45 +0200 Subject: [PATCH 4/7] wip --- packages/backend/src/QueryEngine.ts | 11 +++++ .../src/execution/composeExecutionResults.ts | 15 ------- packages/backend/src/execution/execute.ts | 18 +++++++- .../src/execution/execution/executePlan.ts | 1 + .../execution/runSampledValidation.ts | 36 ++++++++++++++++ .../src/execution/execution/shouldYield.ts | 41 +++++++++++++++++++ .../executors/PgExecutor/PgExecutor.test.ts | 8 ++-- .../planning/createExecutionPlan.test.ts | 1 - .../execution/planning/createExecutionPlan.ts | 4 +- .../execution/planning/createPlanningQuery.ts | 4 +- packages/backend/src/execution/types.d.ts | 5 +-- .../src/query/collectColumnReferences.ts | 8 ++-- packages/backend/src/tests/e2e/nxm.test.ts | 1 - packages/backend/src/tests/e2e/select.test.ts | 7 ++-- .../src/tests/e2e/store-with-films.test.ts | 14 ++++--- .../backend/src/tests/generated/schema.ts | 36 ---------------- packages/backend/src/tests/queryEngine.ts | 1 + .../static/reference/assets/navigation.js | 2 +- .../docs/static/reference/assets/search.js | 2 +- .../src/tests/generated/schema.ts | 36 ---------------- .../src/tests/generated/schema.ts | 36 ---------------- packages/introspect/src/generate.ts | 6 +-- packages/queries/src/generated/schema.ts | 36 ---------------- packages/queries/src/query.test.ts | 4 ++ packages/queries/src/query.ts | 28 +++++++------ packages/react/src/test/generated/schema.ts | 36 ---------------- packages/react/src/useSynthql.ts | 15 ++++--- 27 files changed, 167 insertions(+), 245 deletions(-) create mode 100644 packages/backend/src/execution/execution/runSampledValidation.ts create mode 100644 packages/backend/src/execution/execution/shouldYield.ts diff --git a/packages/backend/src/QueryEngine.ts b/packages/backend/src/QueryEngine.ts index a84fa4ae..ee18e870 100644 --- a/packages/backend/src/QueryEngine.ts +++ b/packages/backend/src/QueryEngine.ts @@ -65,6 +65,13 @@ export interface QueryEngineProps { * Whether to log SQL statements or not. */ logging?: boolean; + + /** + * The rate at which rows are sampled for runtime type validation. + * + * Defaults to 0, meaning no validation will be performed. + */ + runtimeValidationSampleRate?: number; } export class QueryEngine { @@ -72,6 +79,7 @@ export class QueryEngine { private schema: string; private prependSql?: string; private executors: Array = []; + private runtimeValidationSampleRate: number; constructor(config: QueryEngineProps) { this.schema = config.schema ?? 'public'; @@ -94,6 +102,8 @@ export class QueryEngine { logging: config.logging, }), ]; + this.runtimeValidationSampleRate = + config.runtimeValidationSampleRate ?? 0; } execute( @@ -117,6 +127,7 @@ export class QueryEngine { executors: this.executors, defaultSchema: opts?.schema ?? this.schema, prependSql: this.prependSql, + runtimeValidationSampleRate: this.runtimeValidationSampleRate, }); if (opts?.returnLastOnly) { diff --git a/packages/backend/src/execution/composeExecutionResults.ts b/packages/backend/src/execution/composeExecutionResults.ts index 54dcab21..85fbbc64 100644 --- a/packages/backend/src/execution/composeExecutionResults.ts +++ b/packages/backend/src/execution/composeExecutionResults.ts @@ -1,4 +1,3 @@ -import { Value } from '@sinclair/typebox/value'; import { Query, QueryResult } from '@synthql/queries'; import { applyCardinality } from '../query/applyCardinality'; import { assertHasKey } from '../util/asserts/assertHasKey'; @@ -19,20 +18,6 @@ export function composeExecutionResults( tree.root.inputQuery.cardinality ?? 'many', ) as QueryResult; - const schema = tree.root.inputQuery.schema; - if (schema) { - const error = Value.Errors(schema, [], result).First(); - if (error) { - // TODO(fhur): Improve error message - const lines = [ - `${error.message} at path: ${error.path}`, - `Value: ${JSON.stringify(error.value)}`, - `Schema: ${JSON.stringify(error.schema, null, 2)}`, - ]; - throw new Error(lines.join('\n')); - } - } - return result; } diff --git a/packages/backend/src/execution/execute.ts b/packages/backend/src/execution/execute.ts index 167b9208..545b4722 100644 --- a/packages/backend/src/execution/execute.ts +++ b/packages/backend/src/execution/execute.ts @@ -1,6 +1,8 @@ import { Query, QueryResult } from '@synthql/queries'; import { composeExecutionResults } from './composeExecutionResults'; import { executePlan } from './execution/executePlan'; +import { runSampledValidation } from './execution/runSampledValidation'; +import { shouldYield } from './execution/shouldYield'; import { createExecutionPlan } from './planning/createExecutionPlan'; import { QueryExecutor } from './types'; @@ -8,6 +10,7 @@ export interface ExecuteProps { executors: Array; defaultSchema: string; prependSql?: string; + runtimeValidationSampleRate?: number; } /** @@ -40,7 +43,18 @@ export async function* execute( const plan = createExecutionPlan(query, props); for await (const resultTree of executePlan(plan, props)) { - // TODO(fhur) see if we can avoid this cast - yield composeExecutionResults(resultTree) as QueryResult; + if (shouldYield(resultTree)) { + // TODO(fhur) see if we can avoid this cast + const results = composeExecutionResults( + resultTree, + ) as QueryResult; + + runSampledValidation({ + rows: results, + schema: query.schema, + sampleRate: props.runtimeValidationSampleRate, + }); + yield results; + } } } diff --git a/packages/backend/src/execution/execution/executePlan.ts b/packages/backend/src/execution/execution/executePlan.ts index 33aa4ea2..a5621912 100644 --- a/packages/backend/src/execution/execution/executePlan.ts +++ b/packages/backend/src/execution/execution/executePlan.ts @@ -52,6 +52,7 @@ export function executePlan( filters: createFilters(planNode), inputQuery: planNode.inputQuery, result: rows, + planNode, children: [], }; }, diff --git a/packages/backend/src/execution/execution/runSampledValidation.ts b/packages/backend/src/execution/execution/runSampledValidation.ts new file mode 100644 index 00000000..42e2acce --- /dev/null +++ b/packages/backend/src/execution/execution/runSampledValidation.ts @@ -0,0 +1,36 @@ +import { TSchema } from '@sinclair/typebox'; +import { Value, ValueError } from '@sinclair/typebox/value'; + +export function runSampledValidation({ + schema, + sampleRate, + rows, +}: { + schema?: TSchema; + sampleRate?: number; + rows: unknown; +}) { + if (sampleRate === undefined || schema === undefined) { + return; + } + + const shouldSample = Math.random() < sampleRate; + if (!shouldSample) { + return; + } + const msg = `Validating ${Array.isArray(rows) ? rows.length : '1'} rows`; + console.time(msg); + const error = Value.Errors(schema, rows).First(); + console.timeEnd(msg); + if (error) { + throw new Error(formatError(error)); + } +} + +function formatError(error: ValueError) { + return [ + `Validation error at ${error.path}: ${error.message}`, + `Actual: ${error.value}`, + `Expected schema: ${error.schema}`, + ].join('\n'); +} diff --git a/packages/backend/src/execution/execution/shouldYield.ts b/packages/backend/src/execution/execution/shouldYield.ts new file mode 100644 index 00000000..a43fe8c3 --- /dev/null +++ b/packages/backend/src/execution/execution/shouldYield.ts @@ -0,0 +1,41 @@ +import { ExecResultNode, ExecResultTree } from '../types'; + +/** + * Looks at the execution tree and determines if we should yield results to the client. + * + * The current implementation should only yield once - when all planning nodes have been + * executed. + */ +export function shouldYield(tree: ExecResultTree): boolean { + return shouldYieldNode(tree.root); +} + +/** + * Recursively checks if we should yield for a given node. + * + * As a reminder, an `ExecResultNode` is by definition, the execution of the planned node + * (i.e. the node that was initially planned). + * + * An ExecResultNode might have planned children, but no executed children. This indicates that + * execution has not finished for the children. + */ +function shouldYieldNode(node: ExecResultNode): boolean { + const plannedChildren = node.planNode.children; + const executedChildren = node.children; + + // If the number of executed children is less than the number of planned children, + // we should not yield yet + if (executedChildren.length < plannedChildren.length) { + return false; + } + + // Recursively check all executed children + for (const child of executedChildren) { + if (!shouldYieldNode(child)) { + return false; + } + } + + // If we've reached this point, all children (and their descendants) are fully executed + return true; +} diff --git a/packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts b/packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts index 24b122b5..a1202011 100644 --- a/packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts +++ b/packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts @@ -66,11 +66,11 @@ describe('PgExecutor', () => { ]); }); - const q2 = from('actor') - .columns('actor_id', 'first_name', 'last_name') - .take(2); - it('Actor table SynthQL query executes to expected result', async () => { + const q2 = from('actor') + .columns('actor_id', 'first_name', 'last_name') + .take(2); + const result = await executor.execute(q2, executeProps); expect(result).toEqual([ diff --git a/packages/backend/src/execution/planning/createExecutionPlan.test.ts b/packages/backend/src/execution/planning/createExecutionPlan.test.ts index 6aecb047..c4705331 100644 --- a/packages/backend/src/execution/planning/createExecutionPlan.test.ts +++ b/packages/backend/src/execution/planning/createExecutionPlan.test.ts @@ -8,7 +8,6 @@ import { PgExecutor } from '../executors/PgExecutor'; import { QueryProviderExecutor } from '../executors/QueryProviderExecutor'; import { createExecutionPlan } from './createExecutionPlan'; import { simplifyPlan } from './simplifyPlan'; -import { DB } from '../../tests/generated'; describe('createExecutionPlan', () => { test('find film', async () => { diff --git a/packages/backend/src/execution/planning/createExecutionPlan.ts b/packages/backend/src/execution/planning/createExecutionPlan.ts index f83e6b9f..99fa9ab6 100644 --- a/packages/backend/src/execution/planning/createExecutionPlan.ts +++ b/packages/backend/src/execution/planning/createExecutionPlan.ts @@ -1,4 +1,4 @@ -import { AnyQuery } from '@synthql/queries'; +import { Query } from '@synthql/queries'; import { collectColumnReferences } from '../../query/collectColumnReferences'; import { createRefContext } from '../../refs/RefContext'; import { ExecuteProps } from '../execute'; @@ -7,7 +7,7 @@ import { assignExecutors } from './assignExecutors'; import { createPlanningQuery } from './createPlanningQuery'; export function createExecutionPlan( - query: AnyQuery, + query: Query, props: ExecuteProps, ): ExecPlanTree { const { defaultSchema } = props; diff --git a/packages/backend/src/execution/planning/createPlanningQuery.ts b/packages/backend/src/execution/planning/createPlanningQuery.ts index 0e6322f1..09a9be9d 100644 --- a/packages/backend/src/execution/planning/createPlanningQuery.ts +++ b/packages/backend/src/execution/planning/createPlanningQuery.ts @@ -1,8 +1,8 @@ -import { AnyQuery } from '@synthql/queries'; +import { Query } from '@synthql/queries'; import { mapQuery } from '../../query/mapQuery'; import { PlanningQuery } from '../types'; -export function createPlanningQuery(query: AnyQuery): PlanningQuery { +export function createPlanningQuery(query: Query): PlanningQuery { return mapQuery(query, (q, context): PlanningQuery => { return { ...q, diff --git a/packages/backend/src/execution/types.d.ts b/packages/backend/src/execution/types.d.ts index 3df2b411..e819fe45 100644 --- a/packages/backend/src/execution/types.d.ts +++ b/packages/backend/src/execution/types.d.ts @@ -1,7 +1,5 @@ -import { AnyDB, AnyQuery, RefOp } from '@synthql/queries'; +import { AnyQuery } from '@synthql/queries'; import { RefContext } from '../refs/RefContext'; -import { ColumnRef } from '../refs/ColumnRef'; -import { QueryNode } from '../query/createQueryTree'; /** * # Execution Plan @@ -158,6 +156,7 @@ export interface ExecResultNode { * The original query that was executed. */ inputQuery: AnyQuery; + planNode: ExecutionPlanNode; children: ExecResultNode[]; } diff --git a/packages/backend/src/query/collectColumnReferences.ts b/packages/backend/src/query/collectColumnReferences.ts index 01317005..08b18073 100644 --- a/packages/backend/src/query/collectColumnReferences.ts +++ b/packages/backend/src/query/collectColumnReferences.ts @@ -1,8 +1,8 @@ import { AnyQuery, isRefOp } from '@synthql/queries'; -import { TableRef } from '../refs/TableRef'; +import { Path } from '../execution/types'; import { ColumnRef } from '../refs/ColumnRef'; +import { TableRef } from '../refs/TableRef'; import { collectFromQuery } from './collectFromQuery'; -import { Path } from '../execution/types'; type ColumnWithPath = { column: ColumnRef; @@ -10,7 +10,9 @@ type ColumnWithPath = { }; /** - * Recursively collects all unique columns referenced in the query. + * Recursively collects all unique [column references](../refs/ColumnRef.ts) in the query. + * + * Column references are created by `col('table.column')` */ export function collectColumnReferences( query: AnyQuery, diff --git a/packages/backend/src/tests/e2e/nxm.test.ts b/packages/backend/src/tests/e2e/nxm.test.ts index 851689d4..8dd53b13 100644 --- a/packages/backend/src/tests/e2e/nxm.test.ts +++ b/packages/backend/src/tests/e2e/nxm.test.ts @@ -41,7 +41,6 @@ describe('n x m', () => { executors: [ new PgExecutor({ defaultSchema: 'public', - logging: true, pool, }), ], diff --git a/packages/backend/src/tests/e2e/select.test.ts b/packages/backend/src/tests/e2e/select.test.ts index db50090c..8f4e7317 100644 --- a/packages/backend/src/tests/e2e/select.test.ts +++ b/packages/backend/src/tests/e2e/select.test.ts @@ -1,13 +1,12 @@ -import { Query, Table, col } from '@synthql/queries'; +import { Query, col } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { collectLast } from '../..'; -import { DB } from '../generated'; import { sql } from '../postgres'; import { findActorById, findCityById, from, movie } from '../queries'; import { queryEngine } from '../queryEngine'; describe('select', () => { - function run, T extends Query>(query: T) { + function run(query: T) { return collectLast(queryEngine.execute(query)); } @@ -22,7 +21,7 @@ describe('select', () => { const result = await run(findActorById(actorId)); const expected = await sql` - SELECT + SELECT actor.actor_id, actor.first_name, actor.last_name, diff --git a/packages/backend/src/tests/e2e/store-with-films.test.ts b/packages/backend/src/tests/e2e/store-with-films.test.ts index 459a7601..de100a94 100644 --- a/packages/backend/src/tests/e2e/store-with-films.test.ts +++ b/packages/backend/src/tests/e2e/store-with-films.test.ts @@ -7,7 +7,8 @@ import { describeQuery } from '../../query/describeQuery'; import { assertPresent } from '../../util/asserts/assertPresent'; import { compareInventory } from '../compareInventory'; import { sql } from '../postgres'; -import { actor, film, filmActor, inventory, store } from '../queries.v2'; +import { from } from '../queries'; +import { actor, filmActor } from '../queries.v2'; import { pool } from '../queryEngine'; describe('e2e', () => { @@ -20,9 +21,11 @@ describe('e2e', () => { .where({ film_id: col('film.film_id') }) .many(); - const inventories = inventory() + const inventories = from('inventory') + .columns('inventory_id', 'film_id') .include({ - film: film() + film: from('film') + .columns('film_id', 'title') .include({ actors }) .where({ film_id: col('inventory.film_id') }) .one(), @@ -30,7 +33,8 @@ describe('e2e', () => { .where({ store_id: col('store.store_id') }) .many(); - const q = store() + const q = from('store') + .columns('store_id', 'address_id') .include({ inventories, }) @@ -39,7 +43,7 @@ describe('e2e', () => { const pgExecutor = new PgExecutor({ defaultSchema: 'public', - logging: true, + logging: false, pool, }); const execProps = { diff --git a/packages/backend/src/tests/generated/schema.ts b/packages/backend/src/tests/generated/schema.ts index 228b4c91..a6f9a6e4 100644 --- a/packages/backend/src/tests/generated/schema.ts +++ b/packages/backend/src/tests/generated/schema.ts @@ -359,7 +359,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -596,7 +595,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -744,7 +742,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1269,7 +1266,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1511,7 +1507,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1656,7 +1651,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2005,7 +1999,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2199,7 +2192,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2341,7 +2333,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2529,7 +2520,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2677,7 +2667,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2949,7 +2938,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3057,7 +3045,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3186,7 +3173,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3272,7 +3258,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3713,7 +3698,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3953,7 +3937,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6282,7 +6265,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6519,7 +6501,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6667,7 +6648,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7192,7 +7172,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7434,7 +7413,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7579,7 +7557,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7928,7 +7905,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8122,7 +8098,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8264,7 +8239,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8452,7 +8426,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8600,7 +8573,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8872,7 +8844,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8980,7 +8951,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9109,7 +9079,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9195,7 +9164,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9636,7 +9604,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9876,7 +9843,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -11865,14 +11831,12 @@ export const schema: Schema = { 'pg_catalog.timestamp': { id: 'pg_catalog.timestamp', type: 'string', - format: 'date-time', description: 'A PG timestamp.\nNote that values of the PG timestamp type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript.\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, 'pg_catalog.timestamptz': { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, diff --git a/packages/backend/src/tests/queryEngine.ts b/packages/backend/src/tests/queryEngine.ts index 81019625..55b47cf0 100644 --- a/packages/backend/src/tests/queryEngine.ts +++ b/packages/backend/src/tests/queryEngine.ts @@ -13,4 +13,5 @@ export const pool = new Pool({ export const queryEngine = new QueryEngine({ pool, schema: 'public', + runtimeValidationSampleRate: 1, }); diff --git a/packages/docs/static/reference/assets/navigation.js b/packages/docs/static/reference/assets/navigation.js index abb0d21d..d37321f8 100644 --- a/packages/docs/static/reference/assets/navigation.js +++ b/packages/docs/static/reference/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA5WXbW/bIBCA/4s/p+vard2Wb2kaad2mNkuiTVNVVRRfGlQCDuAq1rT/Phk78Qv4oF/DwwMcx+V8/zcxsDfJOHki9AVEeqoVTUZJRswmGSdbmeYc9Gk9+KgVfbcxW56Mkhcm0mR8PkrohvFUgUjG90fZzxxUMRPPTEAjo5xo3ZO1wK747Pzzv9HRtyyE2ez4TCmpcGGbxIythedKZrqxMmFArQkd3qmd0IvDxWVfPudExFlLEtNRyTlQ84No0wjXuaCGSdH1tdCu8fJjR7jNpAa7eNjYsI7yoS3lzJ88lDNP4rRmbohIOagT2GcKtPZbauixhqJTkSogBmbVrDo7vlYu39F9yyAKNCKHcwnYG/xQJRF9olvYm6GDmCLzad0pvZXef/l0dtG+E3fGAnY5tDMweq16ZmjJKszY6dxrOq46NBm9ICaMkjoDOnA9zXj05TyDAEUM+Dbd0x1QdIu7HBSDgTdRD0Zvbip5vhXXsPbWpbbtSGJ16QiVBRGUYeAvo15xMydqiTeYUeGSbmBLgrIKw0Qr8sQhJpQHEJNNRHF91X9ZbYkFQg9oIopeSfeKPKXc67IbD7gsE+vqRGtY58bKMV4xQVRxl2G6AxPrKt+idEqpz1iRIe+UqJQJwplBL6SFBY02w1GZJeI8qyJDb7eh4ny/CM8jhBYLGW8E5XmK2mokZPommcDzpCJCnuDDinpVVbtHFNmCcf+2Hd2RjPIuQOfc+X92pBUWMi5gjYfNAiHLEspuFNNURMgTLEVRdej3BhRqsUCUZcpJrsOuCgtWoJvbyeLP4918tpis7hbLRvtKFCtP1qtDPb7r/9DpqST3dSJtG5Uc+VRgeihn/bY+j6p7STZk9KRaR5SVi4U0FkIku6GPobbEQidnaMemgAz1k3YoulurG9mpFPYHX5/RCLsw2gFVpL2m7+DUNEd5AENZrAe22+Rwo+6y/YB2MrjexVzJV5b688/Z8gFGk28wDj6xgyNq/RZxD/bkViPONdS7wJ0NFyVzbgx3elPMvoGH/wmqzOxOEgAA" \ No newline at end of file +window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE5XXXW/aMBQG4P+Sa7au3dpt3FGKtC+1DKpNU1VVrnNorBon2E4FmvbfpzhAHNs5dm/J68ffh+Tub6Zhq7Nx9kjoM4j8REmajbKK6CIbZ+syrzmok/3DByXp20KveTbKnpnIs/HZKKMF47kEkY3vjtjPGuRuJp6YgA6jnCjlYFawD5+effo3OnrLndDFhs+kLCUO2klMtDqey7JSncqEBrkidHikpoGzDucXLj7nRKSpTRLjaMk5UP2DKN2Bq1pQzUrR96xoX7z40APXVanAdB4Xu6xH3tsoZ+HDQzkLHByrZUFEzkG+gW0lQamwsg897EPJR5FKIBpmbav96fjSWqGph7pBCHRFDvMSsNX4pJpE8oyuYauHJqJ3VYj1mzg9vfv88fTc3hO/xQI2NdgnMLmvfctYl+0yY7Pzt+nY61BjdIOY0LJUFdCB7emeJ2/OEwiQRENo0A53iKJD3NQgGQzcif3D5MFNS16vxRWsgnXJ1o5JrC4dQ01BBKkZhMtoEO7aJHXxChkFl7SANYlibQyDbskjh5SlPAQxbCJ2V5fuzbIRE4hdoInYOSU9CAVKedAyA49YJpNq9VZrmPPXyhMvmSByd1Nh3CGTajV3sfRKaUhskzF3SmTOBOFMoxtixaKiOeEoZhJpzu2uQne3S6V5vwivE0ATi4nfSibw3W0TMSd6HZLuQvuSRiRZg/b/bD3umExyF6Bq7v2remgbi4kLWOHLZgIxZQnNOyTGtImYEy0gSdXjdwESVUwgSZlyUqu41caidePr9WTx5+FmPltMbm8Wy459IZI1M3Oqh5Pv++9DJcn9sxqAe2mEtUpNmuw1wPDudifibgMEN1cgjbWiCGjuQRpoRRGwvRFpop1FSOssprlegxj+CjYK0pKH3nltiJYc+ShlaqjOhjU3j9JOYRwSA+WxB1VNZzHGhBBkM/TZbSMm9OYU/TaQQIa+XMyj5O+C/SfTtBTmh9AbbQf2w+i7dps02/QdvP9hjzwEY5VXDQy3O74d3c+6C9q/wm10LssXlofPnzfkQxg9fIPrEIK9OEKr18BOOHC2OripIG0cN7tcEubtGG4Gj5i5A/f/AU5XjAa4FAAA" \ No newline at end of file diff --git a/packages/docs/static/reference/assets/search.js b/packages/docs/static/reference/assets/search.js index 7687d576..08baaced 100644 --- a/packages/docs/static/reference/assets/search.js +++ b/packages/docs/static/reference/assets/search.js @@ -1 +1 @@ -window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file +window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/packages/handler-express/src/tests/generated/schema.ts b/packages/handler-express/src/tests/generated/schema.ts index 228b4c91..a6f9a6e4 100644 --- a/packages/handler-express/src/tests/generated/schema.ts +++ b/packages/handler-express/src/tests/generated/schema.ts @@ -359,7 +359,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -596,7 +595,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -744,7 +742,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1269,7 +1266,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1511,7 +1507,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1656,7 +1651,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2005,7 +1999,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2199,7 +2192,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2341,7 +2333,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2529,7 +2520,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2677,7 +2667,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2949,7 +2938,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3057,7 +3045,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3186,7 +3173,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3272,7 +3258,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3713,7 +3698,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3953,7 +3937,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6282,7 +6265,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6519,7 +6501,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6667,7 +6648,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7192,7 +7172,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7434,7 +7413,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7579,7 +7557,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7928,7 +7905,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8122,7 +8098,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8264,7 +8239,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8452,7 +8426,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8600,7 +8573,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8872,7 +8844,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8980,7 +8951,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9109,7 +9079,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9195,7 +9164,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9636,7 +9604,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9876,7 +9843,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -11865,14 +11831,12 @@ export const schema: Schema = { 'pg_catalog.timestamp': { id: 'pg_catalog.timestamp', type: 'string', - format: 'date-time', description: 'A PG timestamp.\nNote that values of the PG timestamp type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript.\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, 'pg_catalog.timestamptz': { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, diff --git a/packages/handler-next/src/tests/generated/schema.ts b/packages/handler-next/src/tests/generated/schema.ts index 228b4c91..a6f9a6e4 100644 --- a/packages/handler-next/src/tests/generated/schema.ts +++ b/packages/handler-next/src/tests/generated/schema.ts @@ -359,7 +359,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -596,7 +595,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -744,7 +742,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1269,7 +1266,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1511,7 +1507,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1656,7 +1651,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2005,7 +1999,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2199,7 +2192,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2341,7 +2333,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2529,7 +2520,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2677,7 +2667,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2949,7 +2938,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3057,7 +3045,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3186,7 +3173,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3272,7 +3258,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3713,7 +3698,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3953,7 +3937,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6282,7 +6265,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6519,7 +6501,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6667,7 +6648,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7192,7 +7172,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7434,7 +7413,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7579,7 +7557,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7928,7 +7905,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8122,7 +8098,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8264,7 +8239,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8452,7 +8426,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8600,7 +8573,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8872,7 +8844,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8980,7 +8951,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9109,7 +9079,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9195,7 +9164,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9636,7 +9604,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9876,7 +9843,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -11865,14 +11831,12 @@ export const schema: Schema = { 'pg_catalog.timestamp': { id: 'pg_catalog.timestamp', type: 'string', - format: 'date-time', description: 'A PG timestamp.\nNote that values of the PG timestamp type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript.\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, 'pg_catalog.timestamptz': { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, diff --git a/packages/introspect/src/generate.ts b/packages/introspect/src/generate.ts index 49848c5d..5bb7264b 100644 --- a/packages/introspect/src/generate.ts +++ b/packages/introspect/src/generate.ts @@ -1,5 +1,5 @@ -import { ColumnDefProperties } from '@synthql/queries'; import $RefParser from '@apidevtools/json-schema-ref-parser'; +import { ColumnDefProperties } from '@synthql/queries'; import { DomainDetails, EnumDetails, @@ -9,8 +9,8 @@ import { TableDetails, ViewDetails, } from 'extract-pg-schema'; -import { compile, JSONSchema } from 'json-schema-to-typescript'; import fs from 'fs'; +import { compile, JSONSchema } from 'json-schema-to-typescript'; import path from 'path'; type TableOrView = TableDetails | ViewDetails; @@ -471,7 +471,6 @@ function createWellKnownDefs(): Record { 'pg_catalog.timestamp': { id: 'pg_catalog.timestamp', type: 'string', - format: 'date-time', description: [ 'A PG timestamp.', 'Note that values of the PG timestamp type,', @@ -485,7 +484,6 @@ function createWellKnownDefs(): Record { 'pg_catalog.timestamptz': { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: [ 'A PG timestamptz.', 'Note that values of the PG timestamptz type,', diff --git a/packages/queries/src/generated/schema.ts b/packages/queries/src/generated/schema.ts index c8c632e6..928b6974 100644 --- a/packages/queries/src/generated/schema.ts +++ b/packages/queries/src/generated/schema.ts @@ -359,7 +359,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -596,7 +595,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -744,7 +742,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1269,7 +1266,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1511,7 +1507,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1656,7 +1651,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2005,7 +1999,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2199,7 +2192,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2341,7 +2333,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2529,7 +2520,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2677,7 +2667,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2949,7 +2938,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3057,7 +3045,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3186,7 +3173,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3272,7 +3258,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3713,7 +3698,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3953,7 +3937,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6282,7 +6265,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6519,7 +6501,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6667,7 +6648,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7192,7 +7172,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7434,7 +7413,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7579,7 +7557,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7928,7 +7905,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8122,7 +8098,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8264,7 +8239,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8452,7 +8426,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8600,7 +8573,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8872,7 +8844,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8980,7 +8951,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9109,7 +9079,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9195,7 +9164,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9636,7 +9604,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9876,7 +9843,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -11865,14 +11831,12 @@ export const schema: Schema = { 'pg_catalog.timestamp': { id: 'pg_catalog.timestamp', type: 'string', - format: 'date-time', description: 'A PG timestamp.\nNote that values of the PG timestamp type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript.\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, 'pg_catalog.timestamptz': { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, diff --git a/packages/queries/src/query.test.ts b/packages/queries/src/query.test.ts index 831b79a8..c176f523 100644 --- a/packages/queries/src/query.test.ts +++ b/packages/queries/src/query.test.ts @@ -162,6 +162,10 @@ describe('queries', () => { }; }); + test('', () => { + from('actor').groupBy('actor_id'); + }); + test('', () => { const address = from('address').columns('address_id', 'city_id').one(); const staff = from('staff') diff --git a/packages/queries/src/query.ts b/packages/queries/src/query.ts index 72e3bb70..ac4247e6 100644 --- a/packages/queries/src/query.ts +++ b/packages/queries/src/query.ts @@ -2,9 +2,11 @@ import { Static, Type as t, TArray, + TNull, TObject, TPick, TSchema, + TUnion, } from '@sinclair/typebox'; import { Assert } from '@sinclair/typebox/value'; import { getTablePrimaryKeyColumns } from './schema/getTablePrimaryKeyColumns'; @@ -49,7 +51,7 @@ export class QueryBuilder< /** * Sets the limit of the query. */ - limit(limit: number) { + limit(limit: number): QueryBuilder { const query = this.query; return new QueryBuilder( { @@ -67,7 +69,7 @@ export class QueryBuilder< * * Note: {@link many} is an alias for {@link all}. */ - all() { + all(): Query> { return this.many(); } @@ -79,7 +81,7 @@ export class QueryBuilder< * * Note: {@link maybe} is an alias for {@link first}. */ - first() { + first(): Query> { return this.maybe(); } @@ -91,7 +93,7 @@ export class QueryBuilder< * * Note: {@link one} is an alias for {@link firstOrThrow}. */ - firstOrThrow() { + firstOrThrow(): Query { return this.one(); } @@ -100,7 +102,7 @@ export class QueryBuilder< * for the query, and then builds the query. * Shorthand for `.limit(n).all()`. */ - take(take: number) { + take(take: number): Query> { const query = this.query; return new QueryBuilder( { @@ -128,7 +130,7 @@ export class QueryBuilder< /** * @alias {@link firstOrThrow} */ - one() { + one(): Query { const query = this.query; return new QueryBuilder( { @@ -159,7 +161,7 @@ export class QueryBuilder< /** * @alias {@link first} */ - maybe() { + maybe(): Query> { const query = this.query; return new QueryBuilder( { @@ -167,7 +169,7 @@ export class QueryBuilder< limit: 1, cardinality: 'maybe', }, - this.schema, + t.Union([this.schema, t.Null()]), ).build(); } @@ -257,7 +259,7 @@ export class QueryBuilder< /** * @deprecated use {@link defer} instead. */ - lazy() { + lazy(): QueryBuilder { return this.defer(); } @@ -267,7 +269,7 @@ export class QueryBuilder< * * Merging of the queries will happen inside the `QueryEngine`. */ - defer() { + defer(): QueryBuilder { const query = this.query; return new QueryBuilder( { @@ -278,7 +280,9 @@ export class QueryBuilder< ); } - groupBy[]>(...groupBy: TGroupBy) { + groupBy[]>( + ...groupBy: TGroupBy + ): QueryBuilder { const query = this.query; return new QueryBuilder( { @@ -301,7 +305,7 @@ export class QueryBuilder< * .many(); * ``` */ - name(name: string) { + name(name: string): QueryBuilder { const query = this.query; return new QueryBuilder( { diff --git a/packages/react/src/test/generated/schema.ts b/packages/react/src/test/generated/schema.ts index 228b4c91..a6f9a6e4 100644 --- a/packages/react/src/test/generated/schema.ts +++ b/packages/react/src/test/generated/schema.ts @@ -359,7 +359,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -596,7 +595,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -744,7 +742,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1269,7 +1266,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1511,7 +1507,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -1656,7 +1651,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2005,7 +1999,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2199,7 +2192,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2341,7 +2333,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2529,7 +2520,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2677,7 +2667,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -2949,7 +2938,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3057,7 +3045,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3186,7 +3173,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3272,7 +3258,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3713,7 +3698,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -3953,7 +3937,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6282,7 +6265,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6519,7 +6501,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -6667,7 +6648,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7192,7 +7172,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7434,7 +7413,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7579,7 +7557,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -7928,7 +7905,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8122,7 +8098,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8264,7 +8239,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8452,7 +8426,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8600,7 +8573,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8872,7 +8844,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -8980,7 +8951,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9109,7 +9079,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9195,7 +9164,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9636,7 +9604,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -9876,7 +9843,6 @@ export const schema: Schema = { type: { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, @@ -11865,14 +11831,12 @@ export const schema: Schema = { 'pg_catalog.timestamp': { id: 'pg_catalog.timestamp', type: 'string', - format: 'date-time', description: 'A PG timestamp.\nNote that values of the PG timestamp type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript.\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, 'pg_catalog.timestamptz': { id: 'pg_catalog.timestamptz', type: 'string', - format: 'date-time', description: 'A PG timestamptz.\nNote that values of the PG timestamptz type,\nare returned as ISO 8601 strings from the database.\nThis is because that is how they can be best\naccurately processed in JavaScript/TypeScript\nTo convert the string into a `Date` object,\nuse `new Date(dateTimeString)` or `Date.parse(dateTimeString)`', }, diff --git a/packages/react/src/useSynthql.ts b/packages/react/src/useSynthql.ts index aedd6954..511cc42d 100644 --- a/packages/react/src/useSynthql.ts +++ b/packages/react/src/useSynthql.ts @@ -8,16 +8,21 @@ import { useAyncGeneratorQuery } from './useAsyncGeneratorQuery'; type SynthqlQueryOptions = { requestInit?: RequestInit; returnLastOnly?: boolean; - reactQuery?: QueryOptions; + /** + * `@tanstack/react-query` options for the query. + */ + reactQuery?: QueryOptions>>; }; export function useSynthql( query: TQuery, opts: SynthqlQueryOptions = {}, ): UseQueryResult> { + type ResultType = QueryResult; + const { endpoint, requestInit } = useSynthqlContext(); - const enrichedEndpoint = `${endpoint}/${query.name ?? query.from}-${query.hash}`; + const enrichedEndpoint = `${endpoint}/${query.name ?? query.from}`; const mergedRequestInit: RequestInit = { ...requestInit, @@ -34,10 +39,10 @@ export function useSynthql( requestInit: mergedRequestInit, }); - return useAyncGeneratorQuery({ + return useAyncGeneratorQuery({ queryKey, - queryFn: async () => { - return fetchJsonLines>( + queryFn: (): AsyncGenerator => { + return fetchJsonLines( enrichedEndpoint, mergedRequestInit, ); From a8ac7c0c8a7bdb0016b308e075085508801b52ac Mon Sep 17 00:00:00 2001 From: Fernando Hurtado Date: Mon, 30 Sep 2024 13:37:43 +0200 Subject: [PATCH 5/7] wip --- .../backend/src/execution/execution/runSampledValidation.ts | 3 --- packages/handler-express/src/createExpressSynthqlHandler.ts | 2 +- packages/handler-express/src/tests/queryEngine.ts | 2 +- packages/handler-next/src/tests/queryEngine.ts | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/execution/execution/runSampledValidation.ts b/packages/backend/src/execution/execution/runSampledValidation.ts index 42e2acce..9bb3cd7b 100644 --- a/packages/backend/src/execution/execution/runSampledValidation.ts +++ b/packages/backend/src/execution/execution/runSampledValidation.ts @@ -18,10 +18,7 @@ export function runSampledValidation({ if (!shouldSample) { return; } - const msg = `Validating ${Array.isArray(rows) ? rows.length : '1'} rows`; - console.time(msg); const error = Value.Errors(schema, rows).First(); - console.timeEnd(msg); if (error) { throw new Error(formatError(error)); } diff --git a/packages/handler-express/src/createExpressSynthqlHandler.ts b/packages/handler-express/src/createExpressSynthqlHandler.ts index 88fd7dab..d31a3982 100644 --- a/packages/handler-express/src/createExpressSynthqlHandler.ts +++ b/packages/handler-express/src/createExpressSynthqlHandler.ts @@ -1,5 +1,5 @@ import { collectLast, QueryEngine, SynthqlError } from '@synthql/backend'; -import type { Request, Response, RequestHandler } from 'express'; +import type { Request, RequestHandler, Response } from 'express'; /** * Create an Express request handler that can handle SynthQL requests. diff --git a/packages/handler-express/src/tests/queryEngine.ts b/packages/handler-express/src/tests/queryEngine.ts index 71b38dc4..844ce8fe 100644 --- a/packages/handler-express/src/tests/queryEngine.ts +++ b/packages/handler-express/src/tests/queryEngine.ts @@ -1,5 +1,5 @@ -import { Pool } from 'pg'; import { QueryEngine } from '@synthql/backend'; +import { Pool } from 'pg'; import { DB } from './generated'; export const pool = new Pool({ diff --git a/packages/handler-next/src/tests/queryEngine.ts b/packages/handler-next/src/tests/queryEngine.ts index 71b38dc4..844ce8fe 100644 --- a/packages/handler-next/src/tests/queryEngine.ts +++ b/packages/handler-next/src/tests/queryEngine.ts @@ -1,5 +1,5 @@ -import { Pool } from 'pg'; import { QueryEngine } from '@synthql/backend'; +import { Pool } from 'pg'; import { DB } from './generated'; export const pool = new Pool({ From af6f014bcc89a4d3d3ec83b0282932bb766b4de7 Mon Sep 17 00:00:00 2001 From: Fernando Hurtado Date: Mon, 30 Sep 2024 16:24:27 +0200 Subject: [PATCH 6/7] wip --- .../backend/src/execution/planning/createPlanningQuery.test.ts | 2 +- packages/cli/src/e2e.test.ts | 2 +- packages/introspect/src/e2e.test.ts | 2 +- packages/queries/src/query.ts | 3 ++- packages/queries/src/schema/getTableSchema.ts | 3 ++- scripts/compile-executable-examples.cjs | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/execution/planning/createPlanningQuery.test.ts b/packages/backend/src/execution/planning/createPlanningQuery.test.ts index c919c271..09eb38ac 100644 --- a/packages/backend/src/execution/planning/createPlanningQuery.test.ts +++ b/packages/backend/src/execution/planning/createPlanningQuery.test.ts @@ -144,7 +144,7 @@ describe('createPlanningQuery', () => { .one(); const query = from('store') - .columns('store_id') + .select({ store_id: true }) .include({ address, }) diff --git a/packages/cli/src/e2e.test.ts b/packages/cli/src/e2e.test.ts index 37f7156c..9b3f6c64 100644 --- a/packages/cli/src/e2e.test.ts +++ b/packages/cli/src/e2e.test.ts @@ -20,7 +20,7 @@ describe('e2e', () => { test('Write configuration file validation schema to files', async () => { const prettierOptions = await prettier.resolveConfig( - '../../..prettierrc.js', + '../../.prettierrc.js', ); expect(prettierOptions).not.toBe(null); diff --git a/packages/introspect/src/e2e.test.ts b/packages/introspect/src/e2e.test.ts index 78f32ebe..1ef67919 100644 --- a/packages/introspect/src/e2e.test.ts +++ b/packages/introspect/src/e2e.test.ts @@ -5,7 +5,7 @@ import { generate } from './generate'; describe('e2e', () => { test('Generate from Pagila', async () => { const prettierOptions = await prettier.resolveConfig( - '../../..prettierrc.js', + '../../.prettierrc.js', ); expect(prettierOptions).not.toBe(null); diff --git a/packages/queries/src/query.ts b/packages/queries/src/query.ts index ac4247e6..38636166 100644 --- a/packages/queries/src/query.ts +++ b/packages/queries/src/query.ts @@ -203,7 +203,8 @@ export class QueryBuilder< type SelectFromKeys = { [k in TKeys[number]]: true }; const select = keys.reduce((acc, key) => { - return { ...acc, [key]: true }; + acc[key] = true; + return acc; }, {} as SelectFromKeys); return new QueryBuilder( diff --git a/packages/queries/src/schema/getTableSchema.ts b/packages/queries/src/schema/getTableSchema.ts index fcf33ef9..2efab00a 100644 --- a/packages/queries/src/schema/getTableSchema.ts +++ b/packages/queries/src/schema/getTableSchema.ts @@ -39,7 +39,7 @@ function convertToTypeBoxSchema(jsonSchema: any): TSchema { return Type.Integer(jsonSchema); case 'boolean': return Type.Boolean(jsonSchema); - case 'object': + case 'object': { const properties = {}; for (const key in jsonSchema.properties) { // @ts-ignore @@ -48,6 +48,7 @@ function convertToTypeBoxSchema(jsonSchema: any): TSchema { ); } return Type.Object(properties); + } case 'array': return Type.Array(convertToTypeBoxSchema(jsonSchema.items)); default: diff --git a/scripts/compile-executable-examples.cjs b/scripts/compile-executable-examples.cjs index 5ee9a988..a113a154 100644 --- a/scripts/compile-executable-examples.cjs +++ b/scripts/compile-executable-examples.cjs @@ -102,7 +102,7 @@ function generateMarkdown(examples) { async function main() { const examples = parseTestFile(testFilePath); const prettierConfig = await prettier.resolveConfig( - path.join(__dirname, '../..prettierrc.js'), + path.join(__dirname, '../.prettierrc.js'), ); if (!prettierConfig) { From dc7c8a73873c896de6ec3542cef894acbe39fe41 Mon Sep 17 00:00:00 2001 From: Fernando Hurtado Date: Mon, 30 Sep 2024 17:00:58 +0200 Subject: [PATCH 7/7] wip --- .../backend/src/execution/execute.test.ts | 6 +++--- .../executors/PgExecutor/PgExecutor.test.ts | 3 +-- .../executors/PgExecutor/canExecute.test.ts | 2 +- .../convertWhereToQueryProviderInput.test.ts | 7 ++++--- .../planning/createPlanningQuery.test.ts | 3 +-- .../src/query/collectColumnReferences.test.ts | 4 ++-- .../backend/src/query/iterateQuery.test.ts | 4 ++-- .../src/query/iterateResultRow.test.ts | 3 ++- .../src/query/resolveReferences.test.ts | 5 ++--- .../src/tests/benchmarks/bench.test.ts | 3 +-- packages/backend/src/tests/e2e/defer.test.ts | 19 +++++++++++++++++++ packages/backend/src/tests/e2e/nx1.test.ts | 4 ++-- packages/backend/src/tests/e2e/nxm.test.ts | 4 ++-- packages/backend/src/tests/e2e/select.test.ts | 3 ++- .../tests/e2e/store-with-customers.test.ts | 4 ++-- .../src/tests/e2e/store-with-films.test.ts | 3 ++- packages/backend/src/tests/generated/index.ts | 2 +- packages/backend/src/tests/queries.ts | 4 ++-- packages/backend/src/tests/queries.v2.ts | 3 +-- .../backend/src/types/QueryProviderInput.ts | 2 +- packages/cli/src/types/CliConfig.ts | 1 + .../validators/createTableDefTransformers.ts | 2 +- .../static/reference/assets/navigation.js | 2 +- .../docs/static/reference/assets/search.js | 2 +- .../src/tests/generated/index.ts | 2 +- .../handler-next/src/tests/generated/index.ts | 2 +- packages/introspect/src/generate.ts | 2 +- packages/queries/src/col.ts | 5 ++++- packages/queries/src/generated/index.ts | 2 +- packages/queries/src/query.test.ts | 11 ++++++++++- packages/queries/src/query.ts | 12 ++++++++++++ packages/queries/src/types/ColumnReference.ts | 15 ++++++--------- ...lidateNestedQueriesHaveAValidRefOp.test.ts | 5 ++--- packages/react/src/test/generated/index.ts | 2 +- packages/react/src/useSynthql.test.tsx | 4 ++-- packages/ui/public/tmp.ts | 4 ++-- packages/ui/src/components/Editor/types.json | 2 +- 37 files changed, 101 insertions(+), 62 deletions(-) create mode 100644 packages/backend/src/tests/e2e/defer.test.ts diff --git a/packages/backend/src/execution/execute.test.ts b/packages/backend/src/execution/execute.test.ts index 7bfd3d24..97fcadfa 100644 --- a/packages/backend/src/execution/execute.test.ts +++ b/packages/backend/src/execution/execute.test.ts @@ -1,8 +1,8 @@ -import { col, query } from '@synthql/queries'; +import { query } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { collectLast } from '..'; import { QueryProvider } from '../QueryProvider'; -import { DB, schema } from '../tests/generated'; +import { DB, ref, schema } from '../tests/generated'; import { PgCatalogInt4, PgCatalogText } from '../tests/generated/db'; import { execute } from './execute'; import { QueryProviderExecutor } from './executors/QueryProviderExecutor'; @@ -238,7 +238,7 @@ describe('execute', () => { .include({ rating: from('film_rating') .columns('rating') - .where({ film_id: col('film.film_id') }) + .where({ film_id: ref('film.film_id') }) .one(), }) .one(); diff --git a/packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts b/packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts index a1202011..5568a4aa 100644 --- a/packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts +++ b/packages/backend/src/execution/executors/PgExecutor/PgExecutor.test.ts @@ -1,7 +1,6 @@ -import { col } from '@synthql/queries'; import { describe, expect, it } from 'vitest'; import { PgExecutor } from '.'; -import { from } from '../../../tests/generated'; +import { col, from } from '../../../tests/generated'; import { pool } from '../../../tests/queryEngine'; import { QueryProviderExecutor } from '../QueryProviderExecutor'; diff --git a/packages/backend/src/execution/executors/PgExecutor/canExecute.test.ts b/packages/backend/src/execution/executors/PgExecutor/canExecute.test.ts index efa8798e..987bbeb7 100644 --- a/packages/backend/src/execution/executors/PgExecutor/canExecute.test.ts +++ b/packages/backend/src/execution/executors/PgExecutor/canExecute.test.ts @@ -1,6 +1,6 @@ -import { col } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { PgExecutor } from '.'; +import { col } from '../../../tests/generated'; import { actor, film, diff --git a/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.test.ts b/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.test.ts index 5c3cf200..d70f4a0f 100644 --- a/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.test.ts +++ b/packages/backend/src/execution/executors/QueryProviderExecutor/convertWhereToQueryProviderInput.test.ts @@ -1,5 +1,6 @@ -import { col } from '@synthql/queries'; +import {} from '@synthql/queries'; import { describe, expect, test } from 'vitest'; +import { col } from '../../../tests/generated'; import { convertWhereToQueryProviderInput } from './convertWhereToQueryProviderInput'; describe('convertWhereToQueryProviderInput', () => { @@ -52,8 +53,8 @@ describe('convertWhereToQueryProviderInput', () => { { a: { match: 'a%' } }, { a: { ilike: 'a%' } }, { a: 1, b: { not: 2 } }, - { a: col('b.a') }, - { a: col('b.a'), b: 2 }, + { a: col('b.a' as never) }, + { a: col('b.a' as never), b: 2 }, ]; describe('unsupported where clauses', () => { diff --git a/packages/backend/src/execution/planning/createPlanningQuery.test.ts b/packages/backend/src/execution/planning/createPlanningQuery.test.ts index 09eb38ac..1bc032e9 100644 --- a/packages/backend/src/execution/planning/createPlanningQuery.test.ts +++ b/packages/backend/src/execution/planning/createPlanningQuery.test.ts @@ -1,6 +1,5 @@ -import { col } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; -import { from } from '../../tests/generated'; +import { col, from } from '../../tests/generated'; import { store } from '../../tests/queries.v2'; import { printPath } from '../../util/path/printPath'; import { PlanningQuery } from '../types'; diff --git a/packages/backend/src/query/collectColumnReferences.test.ts b/packages/backend/src/query/collectColumnReferences.test.ts index f6c685da..a15188d2 100644 --- a/packages/backend/src/query/collectColumnReferences.test.ts +++ b/packages/backend/src/query/collectColumnReferences.test.ts @@ -1,6 +1,6 @@ -import { AnyQuery, QueryResult, col } from '@synthql/queries'; +import { AnyQuery, QueryResult } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; -import { from } from '../tests/generated'; +import { col, from } from '../tests/generated'; import { city } from '../tests/queries.v2'; import { collectColumnReferences } from './collectColumnReferences'; diff --git a/packages/backend/src/query/iterateQuery.test.ts b/packages/backend/src/query/iterateQuery.test.ts index d6d30bd5..073d2210 100644 --- a/packages/backend/src/query/iterateQuery.test.ts +++ b/packages/backend/src/query/iterateQuery.test.ts @@ -1,7 +1,7 @@ -import { AnyQuery, col } from '@synthql/queries'; +import { AnyQuery } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { Path } from '../execution/types'; -import { from } from '../tests/generated'; +import { col, from } from '../tests/generated'; import { iterateQuery } from './iterateQuery'; describe('iterateQuery', () => { diff --git a/packages/backend/src/query/iterateResultRow.test.ts b/packages/backend/src/query/iterateResultRow.test.ts index 835f7fd2..290e57ef 100644 --- a/packages/backend/src/query/iterateResultRow.test.ts +++ b/packages/backend/src/query/iterateResultRow.test.ts @@ -1,5 +1,6 @@ -import { QueryResult, col } from '@synthql/queries'; +import { QueryResult } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; +import { col } from '../tests/generated'; import { city } from '../tests/queries.v2'; import { iterateResultRows } from './iterateResultRow'; diff --git a/packages/backend/src/query/resolveReferences.test.ts b/packages/backend/src/query/resolveReferences.test.ts index 2c636032..f7eca1d4 100644 --- a/packages/backend/src/query/resolveReferences.test.ts +++ b/packages/backend/src/query/resolveReferences.test.ts @@ -1,9 +1,8 @@ import { describe, expect, test } from 'vitest'; -import { col } from '@synthql/queries'; -import { createRefContext } from '../refs/RefContext'; import { ColumnRef } from '../refs/ColumnRef'; +import { createRefContext } from '../refs/RefContext'; +import { col, from } from '../tests/generated'; import { resolveReferences } from './resolveReferences'; -import { from } from '../tests/generated'; describe('resolveReferences', () => { test('should resolve references', async () => { diff --git a/packages/backend/src/tests/benchmarks/bench.test.ts b/packages/backend/src/tests/benchmarks/bench.test.ts index e79f05ed..be42a8ce 100644 --- a/packages/backend/src/tests/benchmarks/bench.test.ts +++ b/packages/backend/src/tests/benchmarks/bench.test.ts @@ -1,10 +1,9 @@ -import { col } from '@synthql/queries'; import Benchmark from 'benchmark'; import fs from 'fs'; import path from 'path'; import { describe, test } from 'vitest'; import { collectLast } from '../..'; -import { from } from '../generated'; +import { col, from } from '../generated'; import { queryEngine } from '../queryEngine'; describe('Benchmark tests', () => { diff --git a/packages/backend/src/tests/e2e/defer.test.ts b/packages/backend/src/tests/e2e/defer.test.ts new file mode 100644 index 00000000..9894a42d --- /dev/null +++ b/packages/backend/src/tests/e2e/defer.test.ts @@ -0,0 +1,19 @@ +import { describe, test } from 'vitest'; +import { col } from '../generated'; +import { from } from '../queries'; + +describe('defer', () => { + test('top level defer', async () => { + const language = from('language') + .columns('name') + .defer() + .where({ + language_id: col('film.film_id'), + }) + .all(); + + from('film').columns('film_id').include({ + language, + }); + }); +}); diff --git a/packages/backend/src/tests/e2e/nx1.test.ts b/packages/backend/src/tests/e2e/nx1.test.ts index 18c6fb42..d73b58dd 100644 --- a/packages/backend/src/tests/e2e/nx1.test.ts +++ b/packages/backend/src/tests/e2e/nx1.test.ts @@ -1,9 +1,9 @@ -import { Where, col } from '@synthql/queries'; +import { Where } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { collectLast } from '../..'; import { execute } from '../../execution/execute'; import { QueryProviderExecutor } from '../../execution/executors/QueryProviderExecutor'; -import { DB, from } from '../generated'; +import { col, DB, from } from '../generated'; import { provideFilm } from '../provideFilm'; import { provideLanguage } from '../provideLanguage'; diff --git a/packages/backend/src/tests/e2e/nxm.test.ts b/packages/backend/src/tests/e2e/nxm.test.ts index 8dd53b13..1c118374 100644 --- a/packages/backend/src/tests/e2e/nxm.test.ts +++ b/packages/backend/src/tests/e2e/nxm.test.ts @@ -1,4 +1,4 @@ -import { col } from '@synthql/queries'; +import {} from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { collectLast } from '../..'; import { execute } from '../../execution/execute'; @@ -7,7 +7,7 @@ import { createExecutionPlan } from '../../execution/planning/createExecutionPla import { simplifyPlan } from '../../execution/planning/simplifyPlan'; import { describeQuery } from '../../query/describeQuery'; import { compareInventory } from '../compareInventory'; -import { from } from '../generated'; +import { col, from } from '../generated'; import { sql } from '../postgres'; import { pool } from '../queryEngine'; diff --git a/packages/backend/src/tests/e2e/select.test.ts b/packages/backend/src/tests/e2e/select.test.ts index 8f4e7317..cd866664 100644 --- a/packages/backend/src/tests/e2e/select.test.ts +++ b/packages/backend/src/tests/e2e/select.test.ts @@ -1,6 +1,7 @@ -import { Query, col } from '@synthql/queries'; +import { Query } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { collectLast } from '../..'; +import { col } from '../generated'; import { sql } from '../postgres'; import { findActorById, findCityById, from, movie } from '../queries'; import { queryEngine } from '../queryEngine'; diff --git a/packages/backend/src/tests/e2e/store-with-customers.test.ts b/packages/backend/src/tests/e2e/store-with-customers.test.ts index bfdd3d0c..2cdb2351 100644 --- a/packages/backend/src/tests/e2e/store-with-customers.test.ts +++ b/packages/backend/src/tests/e2e/store-with-customers.test.ts @@ -1,11 +1,11 @@ -import { QueryResult, col } from '@synthql/queries'; +import { QueryResult } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { collectLast } from '../..'; import { execute } from '../../execution/execute'; import { PgExecutor } from '../../execution/executors/PgExecutor'; import { describeQuery } from '../../query/describeQuery'; import { assertPresent } from '../../util/asserts/assertPresent'; -import { from } from '../generated'; +import { col, from } from '../generated'; import { sql } from '../postgres'; import { store } from '../queries.v2'; import { pool } from '../queryEngine'; diff --git a/packages/backend/src/tests/e2e/store-with-films.test.ts b/packages/backend/src/tests/e2e/store-with-films.test.ts index de100a94..c281c1c5 100644 --- a/packages/backend/src/tests/e2e/store-with-films.test.ts +++ b/packages/backend/src/tests/e2e/store-with-films.test.ts @@ -1,4 +1,4 @@ -import { QueryResult, col } from '@synthql/queries'; +import { QueryResult } from '@synthql/queries'; import { describe, expect, test } from 'vitest'; import { collectLast } from '../..'; import { execute } from '../../execution/execute'; @@ -6,6 +6,7 @@ import { PgExecutor } from '../../execution/executors/PgExecutor'; import { describeQuery } from '../../query/describeQuery'; import { assertPresent } from '../../util/asserts/assertPresent'; import { compareInventory } from '../compareInventory'; +import { col } from '../generated'; import { sql } from '../postgres'; import { from } from '../queries'; import { actor, filmActor } from '../queries.v2'; diff --git a/packages/backend/src/tests/generated/index.ts b/packages/backend/src/tests/generated/index.ts index 2969889e..58dd1b29 100644 --- a/packages/backend/src/tests/generated/index.ts +++ b/packages/backend/src/tests/generated/index.ts @@ -4,4 +4,4 @@ import { DB } from './db'; import { schema } from './schema'; export type { DB } from './db'; export { schema } from './schema'; -export const from = query(schema).from; +export const { from, ref, col } = query(schema); diff --git a/packages/backend/src/tests/queries.ts b/packages/backend/src/tests/queries.ts index 0b4a85cd..7f4f2c2e 100644 --- a/packages/backend/src/tests/queries.ts +++ b/packages/backend/src/tests/queries.ts @@ -1,5 +1,5 @@ -import { Table, WhereClause, col, query } from '@synthql/queries'; -import { DB, schema } from './generated'; +import { Table, WhereClause, query } from '@synthql/queries'; +import { DB, col, schema } from './generated'; export function from>(table: TTable) { return query(schema).from(table); diff --git a/packages/backend/src/tests/queries.v2.ts b/packages/backend/src/tests/queries.v2.ts index 829041cc..c704c436 100644 --- a/packages/backend/src/tests/queries.v2.ts +++ b/packages/backend/src/tests/queries.v2.ts @@ -1,5 +1,4 @@ -import { col } from '@synthql/queries'; -import { from } from './generated'; +import { col, from } from './generated'; export function language() { return from('language').columns('name', 'language_id'); diff --git a/packages/backend/src/types/QueryProviderInput.ts b/packages/backend/src/types/QueryProviderInput.ts index 3e2a2ab5..f5cf8c7c 100644 --- a/packages/backend/src/types/QueryProviderInput.ts +++ b/packages/backend/src/types/QueryProviderInput.ts @@ -1,4 +1,4 @@ -import { Table, ColumnValue } from '@synthql/queries'; +import { ColumnValue, Table } from '@synthql/queries'; /** * Get all the `whereable` columns in a table and return diff --git a/packages/cli/src/types/CliConfig.ts b/packages/cli/src/types/CliConfig.ts index 9e9230dd..1c93fa92 100644 --- a/packages/cli/src/types/CliConfig.ts +++ b/packages/cli/src/types/CliConfig.ts @@ -1,4 +1,5 @@ import { ColumnDefProperties } from '@synthql/queries'; + export interface CliConfig { /** * Internal. DO NOT USE/SET this option. diff --git a/packages/cli/src/validators/createTableDefTransformers.ts b/packages/cli/src/validators/createTableDefTransformers.ts index a0bb98d2..2c56993e 100644 --- a/packages/cli/src/validators/createTableDefTransformers.ts +++ b/packages/cli/src/validators/createTableDefTransformers.ts @@ -1,11 +1,11 @@ import { ColumnDefProperties } from '@synthql/queries'; -import { SchemaDefOverrides } from '../types/CliConfig'; import { TableColumn, TableDetails, ViewColumn, ViewDetails, } from 'extract-pg-schema'; +import { SchemaDefOverrides } from '../types/CliConfig'; interface TableDefTransformer { test: (tableDetails: TableDetails | ViewDetails) => boolean; diff --git a/packages/docs/static/reference/assets/navigation.js b/packages/docs/static/reference/assets/navigation.js index d37321f8..6b1faed7 100644 --- a/packages/docs/static/reference/assets/navigation.js +++ b/packages/docs/static/reference/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE5XXXW/aMBQG4P+Sa7au3dpt3FGKtC+1DKpNU1VVrnNorBon2E4FmvbfpzhAHNs5dm/J68ffh+Tub6Zhq7Nx9kjoM4j8REmajbKK6CIbZ+syrzmok/3DByXp20KveTbKnpnIs/HZKKMF47kEkY3vjtjPGuRuJp6YgA6jnCjlYFawD5+effo3OnrLndDFhs+kLCUO2klMtDqey7JSncqEBrkidHikpoGzDucXLj7nRKSpTRLjaMk5UP2DKN2Bq1pQzUrR96xoX7z40APXVanAdB4Xu6xH3tsoZ+HDQzkLHByrZUFEzkG+gW0lQamwsg897EPJR5FKIBpmbav96fjSWqGph7pBCHRFDvMSsNX4pJpE8oyuYauHJqJ3VYj1mzg9vfv88fTc3hO/xQI2NdgnMLmvfctYl+0yY7Pzt+nY61BjdIOY0LJUFdCB7emeJ2/OEwiQRENo0A53iKJD3NQgGQzcif3D5MFNS16vxRWsgnXJ1o5JrC4dQ01BBKkZhMtoEO7aJHXxChkFl7SANYlibQyDbskjh5SlPAQxbCJ2V5fuzbIRE4hdoInYOSU9CAVKedAyA49YJpNq9VZrmPPXyhMvmSByd1Nh3CGTajV3sfRKaUhskzF3SmTOBOFMoxtixaKiOeEoZhJpzu2uQne3S6V5vwivE0ATi4nfSibw3W0TMSd6HZLuQvuSRiRZg/b/bD3umExyF6Bq7v2remgbi4kLWOHLZgIxZQnNOyTGtImYEy0gSdXjdwESVUwgSZlyUqu41caidePr9WTx5+FmPltMbm8Wy459IZI1M3Oqh5Pv++9DJcn9sxqAe2mEtUpNmuw1wPDudifibgMEN1cgjbWiCGjuQRpoRRGwvRFpop1FSOssprlegxj+CjYK0pKH3nltiJYc+ShlaqjOhjU3j9JOYRwSA+WxB1VNZzHGhBBkM/TZbSMm9OYU/TaQQIa+XMyj5O+C/SfTtBTmh9AbbQf2w+i7dps02/QdvP9hjzwEY5VXDQy3O74d3c+6C9q/wm10LssXlofPnzfkQxg9fIPrEIK9OEKr18BOOHC2OripIG0cN7tcEubtGG4Gj5i5A/f/AU5XjAa4FAAA" \ No newline at end of file +window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE5WXbW/aMBCA/0s+s3Xt1m7jG6VIe1PLoNo0VVXlOkexapxgOxVo2n+f4gTi2M7Z/Uqee/x2d9h3fzMNO52Ns0dCn0HkJ0rSbJSVRK+zcbYp8oqDOmk/PihJ3671hmej7JmJPBufjTK6ZjyXILLx3VH2swK5n4knJqCTUU6UcmQW2Befnn36Nzr6lnuh11s+k7KQuNAmMaM18FwWpeqsTGiQK0KHZ2oCnH04v3Dlc05EmrUmMR0tOAeqfxClO+GqElSzQvR9Fto3XnzoCTdlocAMHjd2rKe8t6WchZOHchZIHCtyTUTOQb6BXSlBqbClhR5aKDkVqQSiYdZEtdnxpXGFlh4aBlGgO3JYl4CdxhdVE8kruoadHlqI3pchrR/ijPTu88fTc/tM/IgFbCuwMzB5rDYyNmSzzdjq/GM6jjoUjB4QE1oWqgQ6cDzd9+TDeQIBkmgITdrRHVB0itsKJIOBmmg/Jk9uWvBqI65gFexLtu1IYn3pCNUNEaRmEG6jQXEXkzTEK8yocEnXsCFRWYNholvyyCFlKw8gJpuI/dWlW1m2xACxApqIvdPSg6JAKw+6zMQjLsOkunq7Nazz98ozXjJB5P6mxHQHJtVV12LhtdKQsSFj3imROROEM40eiIVFjSbDUZkh0jy3+xI93Y5K8/0ivEoQGixm/FYwgZ9uQ8Q80XJIqoXmkkYk2YD2/2w93ZFM8i5AVdz7V/WkDRYzLmCFb5sBYpYl1HdITNMQMU+0gSR1j99rkKjFAEmWKSeVirsaLNo3vl5PFn8ebuazxeT2ZrHstC9EsnplTvdw+L7/fagluX9WA+IejWitVpNm9gIweVfdiXI3AJGbEkjTWigiNHWQJrRQRNhURJrRZhGllYtpXi8gJn+FNiqkBQ/deW0RLbh71x01j/hsnOVQSqBEQ57ZN3Q11HzDQ7g88ghmyumWQ8ZAz+yJynqwmMZAiGQ79Ba3JQZ6c4o+GCSQoeeM+ZT8WGjfUdNCmB9C19xO2IfRC3hDmmP6Dt6fs6c8gLF2rAam2+V0p+6z7ob267pB57J4YXk4/7wpH2A0+Qb3IST2cEStXiN24EBudeK6rTQ47uy4JJl3YrgzmGKmBu7/A9HPtazNFAAA" \ No newline at end of file diff --git a/packages/docs/static/reference/assets/search.js b/packages/docs/static/reference/assets/search.js index 08baaced..e79b5851 100644 --- a/packages/docs/static/reference/assets/search.js +++ b/packages/docs/static/reference/assets/search.js @@ -1 +1 @@ -window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file +window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file diff --git a/packages/handler-express/src/tests/generated/index.ts b/packages/handler-express/src/tests/generated/index.ts index 2969889e..58dd1b29 100644 --- a/packages/handler-express/src/tests/generated/index.ts +++ b/packages/handler-express/src/tests/generated/index.ts @@ -4,4 +4,4 @@ import { DB } from './db'; import { schema } from './schema'; export type { DB } from './db'; export { schema } from './schema'; -export const from = query(schema).from; +export const { from, ref, col } = query(schema); diff --git a/packages/handler-next/src/tests/generated/index.ts b/packages/handler-next/src/tests/generated/index.ts index 2969889e..58dd1b29 100644 --- a/packages/handler-next/src/tests/generated/index.ts +++ b/packages/handler-next/src/tests/generated/index.ts @@ -4,4 +4,4 @@ import { DB } from './db'; import { schema } from './schema'; export type { DB } from './db'; export { schema } from './schema'; -export const from = query(schema).from; +export const { from, ref, col } = query(schema); diff --git a/packages/introspect/src/generate.ts b/packages/introspect/src/generate.ts index 5bb7264b..374fd638 100644 --- a/packages/introspect/src/generate.ts +++ b/packages/introspect/src/generate.ts @@ -140,7 +140,7 @@ export async function generate({ `import { schema } from './schema';`, `export type { DB } from './db';`, `export { schema } from './schema';`, - `export const from = query(schema).from;`, + `export const { from, ref, col } = query(schema);`, ].join('\n'), ); diff --git a/packages/queries/src/col.ts b/packages/queries/src/col.ts index c6882d97..8a064680 100644 --- a/packages/queries/src/col.ts +++ b/packages/queries/src/col.ts @@ -1,8 +1,11 @@ import { ColumnReference } from './types/ColumnReference'; import { RefOp } from './types/RefOp'; +/** + * @deprecated Use `ref` instead. + */ export function col(ref: ColumnReference): RefOp { - const parts = ref.split('.'); + const parts = String(ref).split('.'); if (parts.length === 2) { return { $ref: { diff --git a/packages/queries/src/generated/index.ts b/packages/queries/src/generated/index.ts index 295d5b62..23c910d8 100644 --- a/packages/queries/src/generated/index.ts +++ b/packages/queries/src/generated/index.ts @@ -4,4 +4,4 @@ import { DB } from './db'; import { schema } from './schema'; export type { DB } from './db'; export { schema } from './schema'; -export const from = query(schema).from; +export const { from, ref, col } = query(schema); diff --git a/packages/queries/src/query.test.ts b/packages/queries/src/query.test.ts index c176f523..fb8f1993 100644 --- a/packages/queries/src/query.test.ts +++ b/packages/queries/src/query.test.ts @@ -1,5 +1,5 @@ import { describe, test } from 'vitest'; -import { AnyQuery, Query, QueryResult, col } from '.'; +import { AnyQuery, Query, QueryResult, RefOp, Table } from '.'; import { from } from './generated'; describe('queries', () => { @@ -116,6 +116,15 @@ describe('queries', () => { }; }); + function col(ref: Table): RefOp { + return { + $ref: { + column: '', + table: '', + }, + }; + } + test('Find film with language and actors', () => { const language = from('language') .columns('language_id', 'name') diff --git a/packages/queries/src/query.ts b/packages/queries/src/query.ts index 38636166..7a5112fb 100644 --- a/packages/queries/src/query.ts +++ b/packages/queries/src/query.ts @@ -9,11 +9,14 @@ import { TUnion, } from '@sinclair/typebox'; import { Assert } from '@sinclair/typebox/value'; +import { col } from './col'; import { getTablePrimaryKeyColumns } from './schema/getTablePrimaryKeyColumns'; import { getTableSchema } from './schema/getTableSchema'; import { getTableSelectableColumns } from './schema/getTableSelectableColumns'; import { Column } from './types/Column'; +import { ColumnReference } from './types/ColumnReference'; import { ColumnValue } from './types/ColumnValue'; +import { RefOp } from './types/RefOp'; import { Schema } from './types/Schema'; import { Select } from './types/Select'; import { Table } from './types/Table'; @@ -320,6 +323,15 @@ export class QueryBuilder< export function query(schema: Schema) { return { + ref(ref: ColumnReference): RefOp { + return col(ref); + }, + /** + * @deprecated Use {@link ref} instead. + */ + col(ref: ColumnReference): RefOp { + return col(ref); + }, from>(table: TTable) { const select = getTableSelectableColumns(schema, table); diff --git a/packages/queries/src/types/ColumnReference.ts b/packages/queries/src/types/ColumnReference.ts index 87a06065..ec4261f1 100644 --- a/packages/queries/src/types/ColumnReference.ts +++ b/packages/queries/src/types/ColumnReference.ts @@ -6,12 +6,9 @@ * Example: `users.id` */ -export type ColumnReference = { - [TTable in keyof DB]: DB[TTable] extends object - ? `${TTable & string}.${DB[TTable] extends { - columns: infer C; - } - ? keyof C - : string}` - : never; -}[keyof DB]; +import { Column } from './Column'; +import { Table } from './Table'; + +type AllRefs = { [table in Table]: `${table}.${Column}` }; + +export type ColumnReference = AllRefs[keyof AllRefs]; diff --git a/packages/queries/src/validators/validateNestedQueriesHaveAValidRefOp.test.ts b/packages/queries/src/validators/validateNestedQueriesHaveAValidRefOp.test.ts index 84ee449b..fe2d56f2 100644 --- a/packages/queries/src/validators/validateNestedQueriesHaveAValidRefOp.test.ts +++ b/packages/queries/src/validators/validateNestedQueriesHaveAValidRefOp.test.ts @@ -1,6 +1,5 @@ import { describe, expect, test } from 'vitest'; -import { col } from '../col'; -import { from } from '../generated'; +import { from, ref } from '../generated'; describe('validateNestedQueriesHaveAValidRefOp', () => { test('Check that included query without RefOp where clause throws', () => { @@ -19,7 +18,7 @@ describe('validateNestedQueriesHaveAValidRefOp', () => { .include({ lang: from('language') .where({ - language_id: col('film.language_id'), + language_id: ref('film.language_id'), }) .many(), }) diff --git a/packages/react/src/test/generated/index.ts b/packages/react/src/test/generated/index.ts index 2969889e..58dd1b29 100644 --- a/packages/react/src/test/generated/index.ts +++ b/packages/react/src/test/generated/index.ts @@ -4,4 +4,4 @@ import { DB } from './db'; import { schema } from './schema'; export type { DB } from './db'; export { schema } from './schema'; -export const from = query(schema).from; +export const { from, ref, col } = query(schema); diff --git a/packages/react/src/useSynthql.test.tsx b/packages/react/src/useSynthql.test.tsx index e549c14c..8725cee3 100644 --- a/packages/react/src/useSynthql.test.tsx +++ b/packages/react/src/useSynthql.test.tsx @@ -1,11 +1,11 @@ import { QueryEngine } from '@synthql/backend'; -import { col, Query } from '@synthql/queries'; +import { Query } from '@synthql/queries'; import { renderHook } from '@testing-library/react-hooks'; import React from 'react'; import { afterAll, beforeAll, describe, expect, test } from 'vitest'; import { useSynthql } from '.'; import { createPagilaServer, PagilaServer } from './test/createPagilaServer'; -import { from } from './test/generated'; +import { col, from } from './test/generated'; import { Providers } from './test/Providers'; function renderSynthqlQuery({ diff --git a/packages/ui/public/tmp.ts b/packages/ui/public/tmp.ts index c0922a16..c33202c4 100644 --- a/packages/ui/public/tmp.ts +++ b/packages/ui/public/tmp.ts @@ -1,4 +1,4 @@ -import { query, col } from '@synthql/queries'; +import { query } from '@synthql/queries'; interface DB { 'information_schema.tables': { @@ -49,7 +49,7 @@ interface DB { }; } -const from = query().from; +const { from, col } = query(); const keys = from('information_schema.key_column_usage') .columns('column_name', 'table_name') diff --git a/packages/ui/src/components/Editor/types.json b/packages/ui/src/components/Editor/types.json index 21b383d5..57e20e1a 100644 --- a/packages/ui/src/components/Editor/types.json +++ b/packages/ui/src/components/Editor/types.json @@ -1,7 +1,7 @@ [ { "module": "backend", - "types": "\n\n\n\n/// \ndeclare module \"@synthql/backend/src/types/index\" {\n import { JoinOp, Query } from '@synthql/queries';\n import { BinaryOperator } from 'kysely';\n export type AnyDb = Record>;\n export type AnyQuery = Query;\n export type AnyTable = string;\n export type Cardinality = 'one' | 'maybe' | 'many';\n export interface AugmentedQuery {\n /**\n * A unique identifier for the query, inside the query tree.\n */\n id: string;\n /**\n * A reference to the query that was augmented\n */\n query: AnyQuery;\n depth: number;\n /**\n * The table that the query is selecting from\n */\n from: AugmentedTable;\n /**\n * The columns that the query is selecting.\n */\n select: Array;\n /**\n * The where clause of the query.\n */\n where: Array;\n children: AugmentedQuery[];\n leftJoin?: {\n joinOp: JoinOp;\n joinTable: AugmentedTable;\n ownColumn: AugmentedColumn;\n otherColumn: AugmentedColumn;\n };\n }\n type WhereOp = WhereBinaryOp | WhereRefOp;\n export type OpValue = {\n type: 'column';\n column: AugmentedColumn;\n } | {\n type: 'value';\n value: any;\n };\n export interface WhereBinaryOp {\n type: 'binary';\n lhs: OpValue;\n op: BinaryOperator;\n rhs: OpValue;\n }\n interface WhereRefOp {\n type: 'ref';\n lhs: AugmentedColumn;\n rhs: AugmentedColumn;\n }\n export interface SelectionColumn {\n type: 'column';\n column: string;\n /**\n * A unique identifier for the column, inside the query result.\n * Example:\n *\n * ```\n * select table.alias.column as id\n * from ...\n * ```\n */\n id: string;\n table: AugmentedTable;\n }\n export function isSelectionColumn(selection: SelectionColumn | SelectionJsonbAgg): selection is SelectionColumn;\n export function isSelectionJsonbAgg(selection: SelectionColumn | SelectionJsonbAgg): selection is SelectionJsonbAgg;\n interface SelectionJsonbAgg {\n type: 'jsonb_agg';\n id: string;\n table: AugmentedTable;\n columns: SelectionColumn[];\n includeColumn: string;\n }\n export interface AugmentedTable {\n alias: string;\n name: string;\n schema: string;\n }\n export interface AugmentedColumn {\n column: string;\n table: AugmentedTable;\n }\n}\ndeclare module \"@synthql/backend/src/cache\" {\n import { Query, QueryResult, Table } from '@synthql/queries';\n export class QueryCache {\n private cache;\n set>(query: Query, result: QueryResult): void;\n get>(query: Query): QueryResult | undefined;\n }\n export function isPlainObject(o: any): o is Object;\n}\ndeclare module \"@synthql/backend/src/escape\" {\n export function escapeColumn(col: string): string;\n}\ndeclare module \"@synthql/backend/src/util/collectFirst\" {\n export function collectFirst(gen: AsyncGenerator): Promise;\n}\ndeclare module \"@synthql/backend/src/types/QueryPlan\" {\n export interface QueryPlan {\n 'Execution Time'?: number;\n 'Planning Time'?: number;\n 'Settings': {};\n 'Triggers': [];\n 'Planning': Planning;\n 'Plan': PlanNode;\n }\n interface Planning {\n 'Local Dirtied Blocks': number;\n 'Local Hit Blocks': number;\n 'Local Read Blocks': number;\n 'Local Written Blocks': number;\n 'Shared Dirtied Blocks': number;\n 'Shared Hit Blocks': number;\n 'Shared Read Blocks': number;\n 'Shared Written Blocks': number;\n 'Temp Read Blocks': number;\n 'Temp Written Blocks': number;\n }\n type PlanNode = PlanLimit | PlanAggregate | PlanNestedLoop | PlanSeqScan | PlanIndexScan;\n interface BasePlan {\n 'Actual Loops': number;\n 'Actual Rows': number;\n 'Actual Startup Time'?: number;\n 'Actual Total Time'?: number;\n 'Local Dirtied Blocks': number;\n 'Local Hit Blocks': number;\n 'Local Read Blocks': number;\n 'Alias'?: string;\n 'Local Written Blocks': number;\n 'Output': string[];\n 'Parallel Aware': boolean;\n 'Plan Rows': number;\n 'Plan Width': number;\n 'Plans'?: PlanNode[];\n 'Shared Dirtied Blocks': number;\n 'Shared Hit Blocks': number;\n 'Shared Read Blocks': number;\n 'Shared Written Blocks': number;\n 'Startup Cost': number;\n 'Total Cost': number;\n 'Temp Read Blocks': number;\n 'Temp Written Blocks': number;\n }\n interface PlanLimit extends BasePlan {\n 'Node Type': 'Limit';\n }\n interface PlanAggregate extends BasePlan {\n 'Node Type': 'Aggregate';\n 'Group Key': string[];\n 'Parent Relationship': 'Outer' | 'Inner';\n 'Partial Mode': 'Simple' | 'Hashed' | 'Mixed';\n 'Strategy': 'Plain' | 'Sorted';\n }\n interface PlanNestedLoop extends BasePlan {\n 'Node Type': 'Nested Loop';\n 'Inner Unique': boolean;\n 'Join Type': 'Left' | 'Inner';\n 'Parent Relationship': 'Outer' | 'Inner';\n 'Shared Dirtied Blocks': number;\n 'Shared Hit Blocks': number;\n 'Shared Read Blocks': number;\n 'Shared Written Blocks': number;\n 'Startup Cost': number;\n 'Total Cost': number;\n 'Temp Read Blocks': number;\n 'Temp Written Blocks': number;\n }\n interface PlanSeqScan extends BasePlan {\n 'Node Type': 'Seq Scan';\n 'Relation Name': string;\n }\n interface PlanIndexScan extends BasePlan {\n 'Node Type': 'Index Scan';\n 'Index Name': string;\n 'Scan Direction': 'Forward' | 'Backward';\n 'Relation Name': string;\n 'Schema': string;\n 'Index Cond'?: string;\n 'Parent Relationship': 'Outer' | 'Inner';\n 'Rows Removed by Index Recheck'?: number;\n }\n}\ndeclare module \"@synthql/backend/src/AugmentedQuery/iterateAugmentedQuery\" {\n import { AugmentedQuery } from \"@synthql/backend/src/types/index\";\n export function iterateAugmentedQuery(query: AugmentedQuery): Generator;\n}\ndeclare module \"@synthql/backend/src/util/isPresent\" {\n export function isPresent(value: T | null | undefined): value is T;\n export function isString(value: unknown): value is string;\n}\ndeclare module \"@synthql/backend/src/AugmentedQuery/augmentQuery\" {\n import { AnyQuery, AugmentedQuery } from \"@synthql/backend/src/types/index\";\n interface AugmentOpts {\n defaultSchema: string;\n depth?: number;\n nodeId?: string;\n includeColumn?: string;\n }\n export function augmentQuery(query: AnyQuery, opts: AugmentOpts): AugmentedQuery;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/composeQuery\" {\n import { Kysely, SelectQueryBuilder } from 'kysely';\n import { AnyQuery, AugmentedQuery } from \"@synthql/backend/src/types/index\";\n export function composeQuery({ defaultSchema, db, query, }: {\n defaultSchema: string;\n db: Kysely;\n query: AnyQuery;\n }): {\n kQuery: SelectQueryBuilder;\n rootQuery: AugmentedQuery;\n };\n}\ndeclare module \"@synthql/backend/src/util/asserts\" {\n export function assertArrayInResult(value: unknown, path: string): Array<{\n [key: string]: any;\n }>;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/applyCardinality\" {\n import { AnyQuery, Cardinality } from \"@synthql/backend/src/types/index\";\n type CardinalityResult = TCardinality extends 'one' ? T : TCardinality extends 'maybe' ? T | null : T[];\n export function applyCardinality(result: Array, cardinality: TCardinality, opts?: {\n query: AnyQuery;\n row: any;\n }): CardinalityResult;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/hydrate\" {\n import { AugmentedQuery } from \"@synthql/backend/src/types/index\";\n interface Row {\n [key: string]: any;\n }\n type AnyQueryResult = undefined | Array | {\n [key: string]: any;\n };\n export function hydrate(data: Array, query: AugmentedQuery): AnyQueryResult;\n}\ndeclare module \"@synthql/backend/src/QueryEngine/QueryEngine\" {\n import { CompiledQuery } from 'kysely';\n import { Pool } from 'pg';\n import { Query, QueryResult, Table } from \"@synthql/queries\";\n import { QueryPlan } from \"@synthql/backend/src/index\";\n export interface QueryProvider> {\n table: TTable;\n execute: (query: TQuery) => Promise>;\n }\n export interface QueryEngineProps {\n url?: string;\n schema?: string;\n providers?: Array>;\n pool?: Pool;\n }\n export class QueryEngine {\n private dialect;\n private db;\n private pool;\n private schema;\n constructor(config: QueryEngineProps);\n execute, TQuery extends Query>(query: TQuery, opts?: {\n schema?: string;\n }): AsyncGenerator>;\n compile(query: T extends Query ? T : never): CompiledQuery;\n explain>(query: Query): Promise;\n private tryToExecute;\n }\n}\ndeclare module \"@synthql/backend/src/index\" {\n export { collectFirst } from \"@synthql/backend/src/util/collectFirst\";\n export type * from \"@synthql/backend/src/types/QueryPlan\";\n export * from \"@synthql/backend/src/AugmentedQuery/iterateAugmentedQuery\";\n export * from \"@synthql/backend/src/QueryEngine/QueryEngine\";\n}\ndeclare module \"@synthql/backend/src/generateSchema\" {\n import { QueryEngine } from \"@synthql/backend/src/index\";\n export interface PgSchema {\n 'information_schema.tables': {\n table_name: string;\n table_schema: string;\n };\n 'information_schema.columns': {\n column_name: string;\n table_name: string;\n table_schema: string;\n data_type: string;\n is_nullable: 'YES' | 'NO';\n udt_name: string;\n udt_schema: string;\n column_default: string | null;\n };\n 'pg_catalog.pg_type': {\n typname: string;\n oid: number;\n };\n 'pg_catalog.pg_enum': {\n enumtypid: number;\n enumlabel: string;\n enumsortorder: number;\n oid: number;\n };\n }\n export type GenerateSchemaConfig = {\n schemas: string[];\n };\n export function generateSchema(queryEngine: QueryEngine, config: GenerateSchemaConfig): Promise<{\n tables: ({\n table_name: string;\n table_schema: string;\n } & {\n columns: ({\n column_name: string;\n data_type: string;\n is_nullable: \"YES\" | \"NO\";\n udt_name: string;\n udt_schema: string;\n } & {})[];\n })[];\n enums: ({\n typname: string;\n } & {\n enumValues: ({\n enumlabel: string;\n } & {})[];\n })[];\n }>;\n}\ndeclare module \"@synthql/backend/src/tests/db\" {\n import type { ColumnType } from 'kysely';\n export type Generated = T extends ColumnType ? ColumnType : ColumnType;\n export type MpaaRating = 'G' | 'NC-17' | 'PG' | 'PG-13' | 'R';\n export type Numeric = ColumnType;\n export type Timestamp = ColumnType;\n export interface Actor {\n actor_id: Generated;\n first_name: string;\n last_name: string;\n last_update: Generated;\n }\n export interface ActorInfo {\n actor_id: number | null;\n film_info: string | null;\n first_name: string | null;\n last_name: string | null;\n }\n export interface Address {\n address: string;\n address_id: Generated;\n address2: string | null;\n city_id: number;\n district: string;\n last_update: Generated;\n phone: string;\n postal_code: string | null;\n }\n export interface Category {\n category_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface City {\n city: string;\n city_id: Generated;\n country_id: number;\n last_update: Generated;\n }\n export interface Country {\n country: string;\n country_id: Generated;\n last_update: Generated;\n }\n export interface Customer {\n active: number | null;\n activebool: Generated;\n address_id: number;\n create_date: Generated;\n customer_id: Generated;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n store_id: number;\n }\n export interface CustomerList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'notes': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Film {\n description: string | null;\n film_id: Generated;\n fulltext: string;\n language_id: number;\n last_update: Generated;\n length: number | null;\n original_language_id: number | null;\n rating: Generated;\n release_year: number | null;\n rental_duration: Generated;\n rental_rate: Generated;\n replacement_cost: Generated;\n special_features: string[] | null;\n title: string;\n }\n export interface FilmActor {\n actor_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmCategory {\n category_id: number;\n film_id: number;\n last_update: Generated;\n }\n export interface FilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface Inventory {\n film_id: number;\n inventory_id: Generated;\n last_update: Generated;\n store_id: number;\n }\n export interface Language {\n language_id: Generated;\n last_update: Generated;\n name: string;\n }\n export interface NicerButSlowerFilmList {\n actors: string | null;\n category: string | null;\n description: string | null;\n fid: number | null;\n length: number | null;\n price: Numeric | null;\n rating: MpaaRating | null;\n title: string | null;\n }\n export interface PaymentP202201 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202202 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202203 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202204 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202205 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202206 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface PaymentP202207 {\n amount: Numeric;\n customer_id: number;\n payment_date: Timestamp;\n payment_id: Generated;\n rental_id: number;\n staff_id: number;\n }\n export interface Rental {\n customer_id: number;\n inventory_id: number;\n last_update: Generated;\n rental_date: Timestamp;\n rental_id: Generated;\n return_date: Timestamp | null;\n staff_id: number;\n }\n export interface SalesByFilmCategory {\n category: string | null;\n total_sales: Numeric | null;\n }\n export interface SalesByStore {\n manager: string | null;\n store: string | null;\n total_sales: Numeric | null;\n }\n export interface Staff {\n active: Generated;\n address_id: number;\n email: string | null;\n first_name: string;\n last_name: string;\n last_update: Generated;\n password: string | null;\n picture: Buffer | null;\n staff_id: Generated;\n store_id: number;\n username: string;\n }\n export interface StaffList {\n 'address': string | null;\n 'city': string | null;\n 'country': string | null;\n 'id': number | null;\n 'name': string | null;\n 'phone': string | null;\n 'sid': number | null;\n 'zip code': string | null;\n }\n export interface Store {\n address_id: number;\n last_update: Generated;\n manager_staff_id: number;\n store_id: Generated;\n }\n export interface DB {\n actor: Actor;\n actor_info: ActorInfo;\n address: Address;\n category: Category;\n city: City;\n country: Country;\n customer: Customer;\n customer_list: CustomerList;\n film: Film;\n film_actor: FilmActor;\n film_category: FilmCategory;\n film_list: FilmList;\n inventory: Inventory;\n language: Language;\n nicer_but_slower_film_list: NicerButSlowerFilmList;\n payment_p2022_01: PaymentP202201;\n payment_p2022_02: PaymentP202202;\n payment_p2022_03: PaymentP202203;\n payment_p2022_04: PaymentP202204;\n payment_p2022_05: PaymentP202205;\n payment_p2022_06: PaymentP202206;\n payment_p2022_07: PaymentP202207;\n rental: Rental;\n sales_by_film_category: SalesByFilmCategory;\n sales_by_store: SalesByStore;\n staff: Staff;\n staff_list: StaffList;\n store: Store;\n }\n}\ndeclare module \"@synthql/backend/src/tests/queryEngine\" {\n import { QueryEngine } from \"@synthql/backend/src/QueryEngine/QueryEngine\";\n import { DB } from \"@synthql/backend/src/tests/db\";\n export const queryEngine: QueryEngine;\n}\ndeclare module \"@synthql/backend/src/generateSchema.test\" { }\ndeclare module \"@synthql/backend/src/tests/postgres\" {\n import pg from 'postgres';\n export const sql: pg.Sql<{}>;\n}\ndeclare module \"@synthql/backend/src/tests/queries\" {\n import { Table, WhereClause } from '@synthql/queries';\n import { DB } from \"@synthql/backend/src/tests/db\";\n export function from>(table: TTable): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function actor(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function findActorById(actorId: number): {\n from: \"actor\";\n where: {\n actor_id: number;\n };\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n export function findActors(): {\n from: \"actor\";\n where: {};\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n export function language(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function findLanguageById(id: WhereClause): import(\"@synthql/queries/src/query\").QueryBuilder;\n }, \"many\", {}, {\n language_id: true;\n name: true;\n last_update: true;\n }, undefined, [\"language_id\"]>;\n export function movie(): import(\"@synthql/queries/src/query\").QueryBuilder;\n };\n select: {\n language_id: true;\n name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"language_id\"];\n };\n film_actor: {\n from: \"film_actor\";\n where: {\n film_id: import(\"@synthql/queries\").RefOp;\n };\n select: {};\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"id\"];\n };\n actors: {\n from: \"actor\";\n where: {\n actor_id: import(\"@synthql/queries\").RefOp;\n };\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n }, {\n title: true;\n description: true;\n release_year: true;\n }, undefined, [\"film_id\"]>;\n export function country(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function city(): import(\"@synthql/queries/src/query\").QueryBuilder;\n };\n select: {\n country_id: true;\n country: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"country_id\"];\n };\n }, {\n city_id: true;\n city: true;\n last_update: true;\n country_id: true;\n }, undefined, [\"city_id\"]>;\n export function findCityById(id: WhereClause): {\n from: \"city\";\n where: {\n city_id: WhereClause;\n };\n select: {\n city_id: true;\n city: true;\n last_update: true;\n country_id: true;\n };\n include: {\n country: {\n from: \"country\";\n where: {\n country_id: WhereClause;\n };\n select: {\n country_id: true;\n country: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"country_id\"];\n };\n };\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: undefined;\n groupingId: [\"city_id\"];\n };\n}\ndeclare module \"@synthql/backend/src/tests/select.test\" { }\ndeclare module \"@synthql/backend/src/util/collectAsync\" {\n export function collectAsync(gen: AsyncGenerator): Promise;\n}\n/**\n * Performs a LEFT JOIN on two arrays using a hash table.\n */\ndeclare function hashLeftJoin(left: TLeft[], right: TRight[], leftKey: (l: TLeft) => string, rightKey: (r: TRight) => string): Array<[TLeft, TRight | undefined]>;\n\n\n declare module \"@synthql/backend\" { export * from \"@synthql/backend/src/index\"; }", + "types": "\n\n\n\n/// \ndeclare module \"@synthql/backend/src/types/index\" {\n import { JoinOp, Query } from '@synthql/queries';\n import { BinaryOperator } from 'kysely';\n export type AnyDb = Record>;\n export type AnyQuery = Query;\n export type AnyTable = string;\n export type Cardinality = 'one' | 'maybe' | 'many';\n export interface AugmentedQuery {\n /**\n * A unique identifier for the query, inside the query tree.\n */\n id: string;\n /**\n * A reference to the query that was augmented\n */\n query: AnyQuery;\n depth: number;\n /**\n * The table that the query is selecting from\n */\n from: AugmentedTable;\n /**\n * The columns that the query is selecting.\n */\n select: Array;\n /**\n * The where clause of the query.\n */\n where: Array;\n children: AugmentedQuery[];\n leftJoin?: {\n joinOp: JoinOp;\n joinTable: AugmentedTable;\n ownColumn: AugmentedColumn;\n otherColumn: AugmentedColumn;\n };\n }\n type WhereOp = WhereBinaryOp | WhereRefOp;\n export type OpValue = {\n type: 'column';\n column: AugmentedColumn;\n } | {\n type: 'value';\n value: any;\n };\n export interface WhereBinaryOp {\n type: 'binary';\n lhs: OpValue;\n op: BinaryOperator;\n rhs: OpValue;\n }\n interface WhereRefOp {\n type: 'ref';\n lhs: AugmentedColumn;\n rhs: AugmentedColumn;\n }\n export interface SelectionColumn {\n type: 'column';\n column: string;\n /**\n * A unique identifier for the column, inside the query result.\n * Example:\n *\n * ```\n * select table.alias.column as id\n * from ...\n * ```\n */\n id: string;\n table: AugmentedTable;\n }\n export function isSelectionColumn(selection: SelectionColumn | SelectionJsonbAgg): selection is SelectionColumn;\n export function isSelectionJsonbAgg(selection: SelectionColumn | SelectionJsonbAgg): selection is SelectionJsonbAgg;\n interface SelectionJsonbAgg {\n type: 'jsonb_agg';\n id: string;\n table: AugmentedTable;\n columns: SelectionColumn[];\n includeColumn: string;\n }\n export interface AugmentedTable {\n alias: string;\n name: string;\n schema: string;\n }\n export interface AugmentedColumn {\n umn: string;\n table: AugmentedTable;\n }\n}\ndeclare module \"@synthql/backend/src/cache\" {\n import { Query, QueryResult, Table } from '@synthql/queries';\n import { DB } from \"@synthql/backend/src/tests/db\";\n export function from>(table: TTable): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function actor(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function findActorById(actorId: number): {\n from: \"actor\";\n where: {\n actor_id: number;\n };\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n export function findActors(): {\n from: \"actor\";\n where: {};\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n export function language(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function findLanguageById(id: WhereClause): import(\"@synthql/queries/src/query\").QueryBuilder;\n }, \"many\", {}, {\n language_id: true;\n name: true;\n last_update: true;\n }, undefined, [\"language_id\"]>;\n export function movie(): import(\"@synthql/queries/src/query\").QueryBuilder;\n };\n select: {\n language_id: true;\n name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"language_id\"];\n };\n film_actor: {\n from: \"film_actor\";\n where: {\n film_id: import(\"@synthql/queries\").RefOp;\n };\n select: {};\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"id\"];\n };\n actors: {\n from: \"actor\";\n where: {\n actor_id: import(\"@synthql/queries\").RefOp;\n };\n select: {\n actor_id: true;\n first_name: true;\n last_name: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"many\";\n lazy: undefined;\n groupingId: [\"actor_id\"];\n };\n }, {\n title: true;\n description: true;\n release_year: true;\n }, undefined, [\"film_id\"]>;\n export function country(): import(\"@synthql/queries/src/query\").QueryBuilder;\n export function city(): import(\"@synthql/queries/src/query\").QueryBuilder;\n };\n select: {\n country_id: true;\n country: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"country_id\"];\n };\n }, {\n city_id: true;\n city: true;\n last_update: true;\n country_id: true;\n }, undefined, [\"city_id\"]>;\n export function findCityById(id: WhereClause): {\n from: \"city\";\n where: {\n city_id: WhereClause;\n };\n select: {\n city_id: true;\n city: true;\n last_update: true;\n country_id: true;\n };\n include: {\n country: {\n from: \"country\";\n where: {\n country_id: WhereClause;\n };\n select: {\n country_id: true;\n country: true;\n last_update: true;\n };\n include: {};\n limit: number | undefined;\n cardinality: \"one\";\n lazy: undefined;\n groupingId: [\"country_id\"];\n };\n };\n limit: number | undefined;\n cardinality: \"maybe\";\n lazy: undefined;\n groupingId: [\"city_id\"];\n };\n}\ndeclare module \"@synthql/backend/src/tests/select.test\" { }\ndeclare module \"@synthql/backend/src/util/collectAsync\" {\n export function collectAsync(gen: AsyncGenerator): Promise;\n}\n/**\n * Performs a LEFT JOIN on two arrays using a hash table.\n */\ndeclare function hashLeftJoin(left: TLeft[], right: TRight[], leftKey: (l: TLeft) => string, rightKey: (r: TRight) => string): Array<[TLeft, TRight | undefined]>;\n\n\n declare module \"@synthql/backend\" { export * from \"@synthql/backend/src/index\"; }", "fileName": "@synthql/backend/index.d.ts" }, {