From d7acf7e6f5cc2b291ccd92a5a8b7f8c668386acd Mon Sep 17 00:00:00 2001 From: anyhowstep <5655961+AnyhowStep@users.noreply.github.com> Date: Mon, 9 Dec 2019 06:21:44 -0500 Subject: [PATCH 1/6] Bad initial attempt at InsertAndFetchRow<>; needs a lot of cleaning up --- .../table-per-type-impl.ts | 5 + .../table-per-type.ts | 37 ++++ .../util/constructor/table-per-type.ts | 24 ++- .../util/execution/insert-and-fetch.ts | 10 + .../util/execution/insert-and-fetch.ts.todo | 58 ----- .../util/execution/insert-row.ts | 118 ++++++++++ .../util/operation/add-parent.ts | 202 ++++++++++++++++-- .../util/predicate/is-table-per-type.ts | 16 ++ .../util/query/implicit-auto-increment.ts | 8 + .../util/query/index.ts | 1 + .../util/query/insertable-column-alias.ts | 14 ++ src/key/util/operation/concat.ts | 16 ++ src/key/util/operation/subtract.ts | 9 + .../table-per-type-util/app-key-example.d.ts | 4 + ...all-table-with-column-must-be-mutable.d.ts | 4 + ...ll-table-with-column-must-be-nullable.d.ts | 4 + 16 files changed, 450 insertions(+), 80 deletions(-) create mode 100644 src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts delete mode 100644 src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts.todo create mode 100644 src/design-pattern-table-per-type/util/execution/insert-row.ts create mode 100644 src/design-pattern-table-per-type/util/query/implicit-auto-increment.ts create mode 100644 src/design-pattern-table-per-type/util/query/insertable-column-alias.ts diff --git a/src/design-pattern-table-per-type/table-per-type-impl.ts b/src/design-pattern-table-per-type/table-per-type-impl.ts index 80b81e4d..fccd5c57 100644 --- a/src/design-pattern-table-per-type/table-per-type-impl.ts +++ b/src/design-pattern-table-per-type/table-per-type-impl.ts @@ -13,6 +13,9 @@ export class TablePerType implements ITablePerTy readonly explicitAutoIncrementValueEnabled : DataT["explicitAutoIncrementValueEnabled"]; + readonly childInsertAndFetchCandidateKeys : DataT["childInsertAndFetchCandidateKeys"]; + readonly parentInsertAndFetchCandidateKeys : DataT["parentInsertAndFetchCandidateKeys"]; + readonly joins : ITablePerType["joins"]; constructor ( @@ -23,6 +26,8 @@ export class TablePerType implements ITablePerTy this.parentTables = data.parentTables; this.autoIncrement = data.autoIncrement; this.explicitAutoIncrementValueEnabled = data.explicitAutoIncrementValueEnabled; + this.childInsertAndFetchCandidateKeys = data.childInsertAndFetchCandidateKeys; + this.parentInsertAndFetchCandidateKeys = data.parentInsertAndFetchCandidateKeys; this.joins = joins; } diff --git a/src/design-pattern-table-per-type/table-per-type.ts b/src/design-pattern-table-per-type/table-per-type.ts index 175223f7..b8f8590c 100644 --- a/src/design-pattern-table-per-type/table-per-type.ts +++ b/src/design-pattern-table-per-type/table-per-type.ts @@ -1,4 +1,5 @@ import {ITable} from "../table"; +import {Key} from "../key"; export interface TablePerTypeData { readonly childTable : ITable, @@ -8,6 +9,23 @@ export interface TablePerTypeData { readonly autoIncrement : readonly string[], readonly explicitAutoIncrementValueEnabled : readonly string[], + + /** + * Some `parentTables` may not have an `autoIncrement` column. + * + * When such a `parentTable` is encountered and + * we call `TablePerTypeUtil.insertAndFetch()`, + * we need to provide explicit values for at least one candidate key + * of the `parentTable`. + * + * A value of `undefined` indicates that we do not need + * to specify any candidate keys. + * + * A valud of `readonly never[]` indicates + * we cannot specify any candidate keys (and cannot perform `.insertAndFetch()`) + */ + readonly childInsertAndFetchCandidateKeys : (readonly Key[])|undefined, + readonly parentInsertAndFetchCandidateKeys : (readonly Key[])|undefined, } export interface ITablePerType { @@ -30,6 +48,9 @@ export interface ITablePerType readonly explicitAutoIncrementValueEnabled : DataT["explicitAutoIncrementValueEnabled"]; + readonly childInsertAndFetchCandidateKeys : DataT["childInsertAndFetchCandidateKeys"]; + readonly parentInsertAndFetchCandidateKeys : DataT["parentInsertAndFetchCandidateKeys"]; + /** * An array of 2-tuples containing table aliases. * @@ -59,3 +80,19 @@ export interface ITablePerType ] )[]; } + +export type InsertableTablePerType = + & ITablePerType + & { + childTable : { insertEnabled : true }, + parentTables : { insertEnabled : true }[], + } +; + +export type TablePerTypeWithInsertAndFetchCandidateKeys = + & ITablePerType + & { + childInsertAndFetchCandidateKeys : readonly Key[], + parentInsertAndFetchCandidateKeys : readonly Key[], + } +; diff --git a/src/design-pattern-table-per-type/util/constructor/table-per-type.ts b/src/design-pattern-table-per-type/util/constructor/table-per-type.ts index 21dbcb7e..2ef11a58 100644 --- a/src/design-pattern-table-per-type/util/constructor/table-per-type.ts +++ b/src/design-pattern-table-per-type/util/constructor/table-per-type.ts @@ -1,4 +1,4 @@ -import {ITable, TableUtil} from "../../../table"; +import {ITable, TableUtil, TableWithAutoIncrement} from "../../../table"; import {TablePerType} from "../../table-per-type-impl"; export function tablePerType ( @@ -8,12 +8,24 @@ export function tablePerType ( parentTables : readonly [], autoIncrement : readonly Extract[], explicitAutoIncrementValueEnabled : readonly TableUtil.ExplicitAutoIncrement[], + childInsertAndFetchCandidateKeys : ( + ChildTableT extends TableWithAutoIncrement ? + undefined : + readonly (ChildTableT["candidateKeys"][number])[] + ), + parentInsertAndFetchCandidateKeys : undefined, }> { return new TablePerType<{ childTable : ChildTableT, parentTables : readonly [], autoIncrement : readonly Extract[], explicitAutoIncrementValueEnabled : readonly TableUtil.ExplicitAutoIncrement[], + childInsertAndFetchCandidateKeys : ( + ChildTableT extends TableWithAutoIncrement ? + undefined : + readonly (ChildTableT["candidateKeys"][number])[] + ), + parentInsertAndFetchCandidateKeys : undefined, }>( { childTable, @@ -30,6 +42,16 @@ export function tablePerType ( [childTable.autoIncrement] : [] ), + childInsertAndFetchCandidateKeys : ( + childTable.autoIncrement == undefined ? + [...childTable.candidateKeys] : + undefined + ) as ( + ChildTableT extends TableWithAutoIncrement ? + undefined : + readonly (ChildTableT["candidateKeys"][number])[] + ), + parentInsertAndFetchCandidateKeys : undefined, }, [], ); diff --git a/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts b/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts new file mode 100644 index 00000000..b629db9d --- /dev/null +++ b/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts @@ -0,0 +1,10 @@ +import {InsertableTablePerType, TablePerTypeWithInsertAndFetchCandidateKeys} from "../../table-per-type"; +import {CustomInsertRow, CustomInsertRowWithCandidateKey} from "./insert-row"; + +export type InsertAndFetchRow< + TptT extends InsertableTablePerType +> = + TptT extends TablePerTypeWithInsertAndFetchCandidateKeys ? + CustomInsertRowWithCandidateKey : + CustomInsertRow +; diff --git a/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts.todo b/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts.todo deleted file mode 100644 index 22a6acd8..00000000 --- a/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts.todo +++ /dev/null @@ -1,58 +0,0 @@ -import {ITablePerType} from "../../table-per-type"; -import {ColumnAlias, ColumnType, RequiredColumnAlias, OptionalColumnAlias} from "../query"; -import {Identity, Merge} from "../../../type-util"; -import {CustomExpr_NonCorrelated} from "../../../custom-expr"; -import {BuiltInExpr_NonCorrelated} from "../../../built-in-expr"; - -export type ValueInsertRow = - Identity< - & { - readonly [columnAlias in RequiredColumnAlias] : ( - ColumnType - ) - } - & { - readonly [columnAlias in OptionalColumnAlias]? : ( - ColumnType - ) - } - > -; - -export type CustomInsertRow = - Identity< - & { - readonly [columnAlias in RequiredColumnAlias] : ( - CustomExpr_NonCorrelated< - ColumnType - > - ) - } - & { - readonly [columnAlias in OptionalColumnAlias]? : ( - CustomExpr_NonCorrelated< - ColumnType - > - ) - } - > -; - -export type BuiltInInsertRow = - Identity< - & { - readonly [columnAlias in RequiredColumnAlias] : ( - BuiltInExpr_NonCorrelated< - ColumnType - > - ) - } - & { - readonly [columnAlias in OptionalColumnAlias]? : ( - BuiltInExpr_NonCorrelated< - ColumnType - > - ) - } - > -; diff --git a/src/design-pattern-table-per-type/util/execution/insert-row.ts b/src/design-pattern-table-per-type/util/execution/insert-row.ts new file mode 100644 index 00000000..27491a61 --- /dev/null +++ b/src/design-pattern-table-per-type/util/execution/insert-row.ts @@ -0,0 +1,118 @@ +import {ITablePerType, TablePerTypeWithInsertAndFetchCandidateKeys} from "../../table-per-type"; +import {ColumnType, RequiredColumnAlias, OptionalColumnAlias, InsertableColumnAlias} from "../query"; +import {Identity} from "../../../type-util"; +import {CustomExpr_NonCorrelated} from "../../../custom-expr"; +import {BuiltInExpr_NonCorrelated} from "../../../built-in-expr"; +import {Key, KeyUtil} from "../../../key"; + +export type ValueInsertRow = + Identity< + & { + readonly [columnAlias in RequiredColumnAlias] : ( + ColumnType + ) + } + & { + readonly [columnAlias in OptionalColumnAlias]? : ( + ColumnType + ) + } + > +; + +export type CustomInsertRow = + Identity< + & { + readonly [columnAlias in RequiredColumnAlias] : ( + CustomExpr_NonCorrelated< + ColumnType + > + ) + } + & { + readonly [columnAlias in OptionalColumnAlias]? : ( + CustomExpr_NonCorrelated< + ColumnType + > + ) + } + > +; + +export type BuiltInInsertRow = + Identity< + & { + readonly [columnAlias in RequiredColumnAlias] : ( + BuiltInExpr_NonCorrelated< + ColumnType + > + ) + } + & { + readonly [columnAlias in OptionalColumnAlias]? : ( + BuiltInExpr_NonCorrelated< + ColumnType + > + ) + } + > +; + +export type CustomInsertRowWithCandidateKey_NonUnion< + TptT extends ITablePerType, + CandidateKeyT extends Key +> = + Identity< + & { + readonly [columnAlias in Exclude, CandidateKeyT[number]>] : ( + CustomExpr_NonCorrelated< + ColumnType + > + ) + } + & { + readonly [columnAlias in Exclude, CandidateKeyT[number]>]? : ( + CustomExpr_NonCorrelated< + ColumnType + > + ) + } + /** + * This Candidate key is required. + */ + & { + readonly [candidateKeyColumnAlias in CandidateKeyT[number]] : ( + CustomExpr_NonCorrelated< + ColumnType + > + ) + } + > +; +export type CustomInsertRowWithCandidateKeyImpl< + TptT extends ITablePerType, + CandidateKeyT extends Key +> = + CandidateKeyT extends Key ? + ( + KeyUtil.IsSubKey[]> extends true ? + CustomInsertRowWithCandidateKey_NonUnion : + never + ) : + never +; +export type CustomInsertRowWithCandidateKey< + TptT extends TablePerTypeWithInsertAndFetchCandidateKeys +> = + TptT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? + never : + TptT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? + never : + CustomInsertRowWithCandidateKeyImpl< + TptT, + KeyUtil.ConcatDistribute< + TptT["childInsertAndFetchCandidateKeys"][number], + TptT["parentInsertAndFetchCandidateKeys"][number] + > + > +; diff --git a/src/design-pattern-table-per-type/util/operation/add-parent.ts b/src/design-pattern-table-per-type/util/operation/add-parent.ts index b2af0b3f..8e3d1e55 100644 --- a/src/design-pattern-table-per-type/util/operation/add-parent.ts +++ b/src/design-pattern-table-per-type/util/operation/add-parent.ts @@ -1,10 +1,10 @@ import {ITablePerType} from "../../table-per-type"; -import {ITable, TableUtil} from "../../../table"; +import {ITable, TableUtil, TableWithAutoIncrement} from "../../../table"; import {ExtractParentTables, ExtractChildTable, extractParentTables, extractChildTable, ColumnAlias, columnAliases} from "../query"; import {TablePerType} from "../../table-per-type-impl"; import {removeDuplicateParents} from "./remove-duplicate-parents"; import {isTablePerType} from "../predicate"; -import {KeyUtil} from "../../../key"; +import {KeyUtil, Key} from "../../../key"; import {Identity} from "../../../type-util"; type ExtractAutoIncrement< @@ -81,61 +81,61 @@ function extractColumnAlias< } type AddParentAutoIncrement< - TablePerTypeT extends ITablePerType, + TptT extends ITablePerType, ParentT extends ITable|ITablePerType > = Identity< | ExtractAutoIncrement | Exclude< - TablePerTypeT["autoIncrement"][number], + TptT["autoIncrement"][number], ExtractColumnAlias > > ; function addParentAutoIncrement< - TablePerTypeT extends ITablePerType, + TptT extends ITablePerType, ParentT extends ITable|ITablePerType > ( - tpt : TablePerTypeT, + tpt : TptT, parent : ParentT -) : AddParentAutoIncrement[] { +) : AddParentAutoIncrement[] { const parentColumnAliases = extractColumnAlias(parent); return KeyUtil.removeDuplicates([ ...extractAutoIncrement(parent), ...tpt.autoIncrement.filter( columnAlias => !parentColumnAliases.includes(columnAlias as any) ), - ]) as AddParentAutoIncrement[]; + ]) as AddParentAutoIncrement[]; } type AddParentExplicitAutoIncrementValueEnabled< - TablePerTypeT extends ITablePerType, + TptT extends ITablePerType, ParentT extends ITable|ITablePerType > = Identity< | Extract< ExtractExplicitAutoIncrementValueEnabled, - TablePerTypeT["explicitAutoIncrementValueEnabled"][number] + TptT["explicitAutoIncrementValueEnabled"][number] > | Exclude< ExtractExplicitAutoIncrementValueEnabled, - TablePerTypeT["autoIncrement"][number] + TptT["autoIncrement"][number] > | Exclude< - TablePerTypeT["explicitAutoIncrementValueEnabled"][number], + TptT["explicitAutoIncrementValueEnabled"][number], ExtractColumnAlias > > ; function addParentExplicitAutoIncrementValueEnabled< - TablePerTypeT extends ITablePerType, + TptT extends ITablePerType, ParentT extends ITable|ITablePerType > ( - tpt : TablePerTypeT, + tpt : TptT, parent : ParentT -) : AddParentExplicitAutoIncrementValueEnabled[] { +) : AddParentExplicitAutoIncrementValueEnabled[] { const parentColumnAliases = extractColumnAlias(parent); return KeyUtil.removeDuplicates([ @@ -148,28 +148,104 @@ function addParentExplicitAutoIncrementValueEnabled< ...tpt.explicitAutoIncrementValueEnabled.filter( columnAlias => !parentColumnAliases.includes(columnAlias as any) ), - ]) as AddParentExplicitAutoIncrementValueEnabled[]; + ]) as AddParentExplicitAutoIncrementValueEnabled[]; } export type AddParent< - TablePerTypeT extends ITablePerType, + TptT extends ITablePerType, ParentT extends ITable|ITablePerType > = TablePerType<{ - childTable : TablePerTypeT["childTable"], + childTable : TptT["childTable"], parentTables : readonly ( - | TablePerTypeT["parentTables"][number] + | TptT["parentTables"][number] | ExtractParentTables | ExtractChildTable )[], autoIncrement : readonly AddParentAutoIncrement< - TablePerTypeT, + TptT, ParentT >[], explicitAutoIncrementValueEnabled : readonly AddParentExplicitAutoIncrementValueEnabled< - TablePerTypeT, + TptT, ParentT >[], + childInsertAndFetchCandidateKeys : ( + TptT["childInsertAndFetchCandidateKeys"] extends undefined ? + undefined : + TptT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? + readonly never[] : + TptT["childInsertAndFetchCandidateKeys"] extends readonly Key[] ? + ( + KeyUtil.SubtractDistribute< + TptT["childInsertAndFetchCandidateKeys"][number], + readonly ExtractColumnAlias[] + > extends readonly never[] ? + undefined : + readonly KeyUtil.SubtractDistribute< + TptT["childInsertAndFetchCandidateKeys"][number], + readonly ExtractColumnAlias[] + >[] + ) : + never + ), + parentInsertAndFetchCandidateKeys : ( + ParentT extends ITablePerType ? + ( + ParentT["childInsertAndFetchCandidateKeys"] extends undefined ? + ( + ParentT["parentInsertAndFetchCandidateKeys"] extends undefined ? + undefined : + ParentT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? + readonly never[] : + ParentT["parentInsertAndFetchCandidateKeys"] extends readonly Key[] ? + readonly ( + Extract< + ParentT["parentInsertAndFetchCandidateKeys"], + readonly Key[] + >[number] + )[] : + never + ) : + ParentT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? + readonly never[] : + ParentT["childInsertAndFetchCandidateKeys"] extends readonly Key[] ? + ( + ParentT["parentInsertAndFetchCandidateKeys"] extends undefined ? + readonly ( + Extract< + ParentT["childInsertAndFetchCandidateKeys"], + readonly Key[] + >[number] + )[] : + ParentT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? + readonly never[] : + ParentT["parentInsertAndFetchCandidateKeys"] extends readonly Key[] ? + readonly KeyUtil.ConcatDistribute< + KeyUtil.SubtractDistribute< + Extract< + ParentT["childInsertAndFetchCandidateKeys"], + readonly Key[] + >[number], + readonly ExtractColumnAlias[] + >, + Extract< + ParentT["parentInsertAndFetchCandidateKeys"], + readonly Key[] + >[number] + >[] : + never + ) : + never + ) : + ParentT extends ITable ? + ( + ParentT extends TableWithAutoIncrement ? + undefined : + readonly (ParentT["candidateKeys"][number])[] + ) : + never + ), }> ; @@ -230,6 +306,82 @@ export function addParent< TptT, ParentT >[], + childInsertAndFetchCandidateKeys : ( + TptT["childInsertAndFetchCandidateKeys"] extends undefined ? + undefined : + TptT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? + readonly never[] : + TptT["childInsertAndFetchCandidateKeys"] extends readonly Key[] ? + ( + KeyUtil.SubtractDistribute< + TptT["childInsertAndFetchCandidateKeys"][number], + readonly ExtractColumnAlias[] + > extends readonly never[] ? + undefined : + readonly KeyUtil.SubtractDistribute< + TptT["childInsertAndFetchCandidateKeys"][number], + readonly ExtractColumnAlias[] + >[] + ) : + never + ), + parentInsertAndFetchCandidateKeys : ( + ParentT extends ITablePerType ? + ( + ParentT["childInsertAndFetchCandidateKeys"] extends undefined ? + ( + ParentT["parentInsertAndFetchCandidateKeys"] extends undefined ? + undefined : + ParentT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? + readonly never[] : + ParentT["parentInsertAndFetchCandidateKeys"] extends readonly Key[] ? + readonly ( + Extract< + ParentT["parentInsertAndFetchCandidateKeys"], + readonly Key[] + >[number] + )[] : + never + ) : + ParentT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? + readonly never[] : + ParentT["childInsertAndFetchCandidateKeys"] extends readonly Key[] ? + ( + ParentT["parentInsertAndFetchCandidateKeys"] extends undefined ? + readonly ( + Extract< + ParentT["childInsertAndFetchCandidateKeys"], + readonly Key[] + >[number] + )[] : + ParentT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? + readonly never[] : + ParentT["parentInsertAndFetchCandidateKeys"] extends readonly Key[] ? + readonly KeyUtil.ConcatDistribute< + KeyUtil.SubtractDistribute< + Extract< + ParentT["childInsertAndFetchCandidateKeys"], + readonly Key[] + >[number], + readonly ExtractColumnAlias[] + >, + Extract< + ParentT["parentInsertAndFetchCandidateKeys"], + readonly Key[] + >[number] + >[] : + never + ) : + never + ) : + ParentT extends ITable ? + ( + ParentT extends TableWithAutoIncrement ? + undefined : + readonly (ParentT["candidateKeys"][number])[] + ) : + never + ), }>( { childTable : tpt.childTable, @@ -240,6 +392,14 @@ export function addParent< ]), autoIncrement : addParentAutoIncrement(tpt, parent), explicitAutoIncrementValueEnabled : addParentExplicitAutoIncrementValueEnabled(tpt, parent), + /** + * @todo + */ + childInsertAndFetchCandidateKeys : null as any, + /** + * @todo + */ + parentInsertAndFetchCandidateKeys : null as any, }, joins ); diff --git a/src/design-pattern-table-per-type/util/predicate/is-table-per-type.ts b/src/design-pattern-table-per-type/util/predicate/is-table-per-type.ts index f67afc5b..9e960529 100644 --- a/src/design-pattern-table-per-type/util/predicate/is-table-per-type.ts +++ b/src/design-pattern-table-per-type/util/predicate/is-table-per-type.ts @@ -15,6 +15,8 @@ export function isTablePerType (mixed : unknown) : mixed is ITablePerType { "parentTables", "autoIncrement", "explicitAutoIncrementValueEnabled", + "childInsertAndFetchCandidateKeys", + "parentInsertAndFetchCandidateKeys", "joins" ] )) { @@ -34,6 +36,20 @@ export function isTablePerType (mixed : unknown) : mixed is ITablePerType { * Does not check if all elements are `string` */ (mixed.explicitAutoIncrementValueEnabled instanceof Array) && + /** + * Does not check if all elements are `string[]` + */ + ( + mixed.childInsertAndFetchCandidateKeys == undefined || + (mixed.childInsertAndFetchCandidateKeys instanceof Array) + ) && + /** + * Does not check if all elements are `string[]` + */ + ( + mixed.parentInsertAndFetchCandidateKeys == undefined || + (mixed.parentInsertAndFetchCandidateKeys instanceof Array) + ) && /** * Does not check if all elements are `string` */ diff --git a/src/design-pattern-table-per-type/util/query/implicit-auto-increment.ts b/src/design-pattern-table-per-type/util/query/implicit-auto-increment.ts new file mode 100644 index 00000000..40ba347d --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/implicit-auto-increment.ts @@ -0,0 +1,8 @@ +import {ITablePerType} from "../../table-per-type"; + +export type ImplicitAutoIncrement = + Exclude< + TptT["autoIncrement"][number], + TptT["explicitAutoIncrementValueEnabled"][number] + > +; diff --git a/src/design-pattern-table-per-type/util/query/index.ts b/src/design-pattern-table-per-type/util/query/index.ts index ad8c4661..f0f465b9 100644 --- a/src/design-pattern-table-per-type/util/query/index.ts +++ b/src/design-pattern-table-per-type/util/query/index.ts @@ -7,6 +7,7 @@ export * from "./extract-parent-tables"; export * from "./extract-table-with-alias"; export * from "./find-last-join-to-table"; export * from "./generated-column-alias"; +export * from "./insertable-column-alias"; export * from "./mutable-column-alias"; export * from "./non-generated-column-alias"; export * from "./nullable-column-alias"; diff --git a/src/design-pattern-table-per-type/util/query/insertable-column-alias.ts b/src/design-pattern-table-per-type/util/query/insertable-column-alias.ts new file mode 100644 index 00000000..5078e7a6 --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/insertable-column-alias.ts @@ -0,0 +1,14 @@ +import {ITablePerType} from "../../table-per-type"; +import {ColumnAlias} from "./column-alias"; +import {GeneratedColumnAlias} from "./generated-column-alias"; +import {ImplicitAutoIncrement} from "./implicit-auto-increment"; + +export type InsertableColumnAlias = + Exclude< + ColumnAlias, + ( + | GeneratedColumnAlias + | ImplicitAutoIncrement + ) + > +; diff --git a/src/key/util/operation/concat.ts b/src/key/util/operation/concat.ts index cab0750f..a19db40c 100644 --- a/src/key/util/operation/concat.ts +++ b/src/key/util/operation/concat.ts @@ -11,6 +11,22 @@ export type Concat< )[] ); +export type ConcatDistribute< + A extends Key, + B extends Key +> = ( + A extends Key ? + ( + B extends Key ? + readonly ( + A[number] | + B[number] + )[] : + never + ) : + never +); + export function concat< A extends Key, B extends Key diff --git a/src/key/util/operation/subtract.ts b/src/key/util/operation/subtract.ts index 7e581e60..7ba4e448 100644 --- a/src/key/util/operation/subtract.ts +++ b/src/key/util/operation/subtract.ts @@ -8,6 +8,15 @@ export type Subtract< readonly Exclude[] ); +export type SubtractDistribute< + A extends Key, + B extends Key +> = + A extends Key ? + readonly Exclude[] : + never +; + export function subtract< A extends Key, B extends Key diff --git a/test/compile-time/expected-output/table-per-type-util/app-key-example.d.ts b/test/compile-time/expected-output/table-per-type-util/app-key-example.d.ts index 4491cbe7..a694a650 100644 --- a/test/compile-time/expected-output/table-per-type-util/app-key-example.d.ts +++ b/test/compile-time/expected-output/table-per-type-util/app-key-example.d.ts @@ -207,6 +207,8 @@ export declare const browserAppKeyTpt: tsql.TablePerType<{ }>[]; autoIncrement: readonly "appKeyId"[]; explicitAutoIncrementValueEnabled: readonly never[]; + childInsertAndFetchCandidateKeys: undefined; + parentInsertAndFetchCandidateKeys: undefined; }>; export declare const serverAppKeyTpt: tsql.TablePerType<{ childTable: tsql.Table<{ @@ -297,4 +299,6 @@ export declare const serverAppKeyTpt: tsql.TablePerType<{ }>[]; autoIncrement: readonly "appKeyId"[]; explicitAutoIncrementValueEnabled: readonly never[]; + childInsertAndFetchCandidateKeys: undefined; + parentInsertAndFetchCandidateKeys: undefined; }>; diff --git a/test/compile-time/expected-output/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.d.ts b/test/compile-time/expected-output/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.d.ts index dc5071a0..b12c8472 100644 --- a/test/compile-time/expected-output/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.d.ts +++ b/test/compile-time/expected-output/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.d.ts @@ -48,6 +48,8 @@ export declare const bTpt: tsql.TablePerType<{ }>[]; autoIncrement: readonly never[]; explicitAutoIncrementValueEnabled: readonly never[]; + childInsertAndFetchCandidateKeys: readonly never[]; + parentInsertAndFetchCandidateKeys: readonly never[]; }>; export declare const cTpt: tsql.TablePerType<{ childTable: tsql.Table<{ @@ -120,6 +122,8 @@ export declare const cTpt: tsql.TablePerType<{ }>)[]; autoIncrement: readonly never[]; explicitAutoIncrementValueEnabled: readonly never[]; + childInsertAndFetchCandidateKeys: readonly never[]; + parentInsertAndFetchCandidateKeys: readonly never[]; }>; export declare const bMutable: "x"[]; export declare const cMutable: never[]; diff --git a/test/compile-time/expected-output/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.d.ts b/test/compile-time/expected-output/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.d.ts index 985af54d..f5c3c99c 100644 --- a/test/compile-time/expected-output/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.d.ts +++ b/test/compile-time/expected-output/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.d.ts @@ -48,6 +48,8 @@ export declare const bTpt: tsql.TablePerType<{ }>[]; autoIncrement: readonly never[]; explicitAutoIncrementValueEnabled: readonly never[]; + childInsertAndFetchCandidateKeys: readonly never[]; + parentInsertAndFetchCandidateKeys: readonly never[]; }>; export declare const cTpt: tsql.TablePerType<{ childTable: tsql.Table<{ @@ -120,6 +122,8 @@ export declare const cTpt: tsql.TablePerType<{ }>)[]; autoIncrement: readonly never[]; explicitAutoIncrementValueEnabled: readonly never[]; + childInsertAndFetchCandidateKeys: readonly never[]; + parentInsertAndFetchCandidateKeys: readonly never[]; }>; export declare const bNullable: "x"[]; export declare const cNullable: never[]; From 83a0289947f97c7f47bf32b264b34f077b8cdc1b Mon Sep 17 00:00:00 2001 From: anyhowstep <5655961+AnyhowStep@users.noreply.github.com> Date: Thu, 12 Dec 2019 11:43:31 -0500 Subject: [PATCH 2/6] Better InsertAndFetchRow<>; hopefully --- src/built-in-expr/built-in-expr.ts | 24 ++ src/custom-expr/custom-expr.ts | 24 ++ .../util/execution/track-or-insert.ts | 10 +- .../util/execution/unsafe-track.ts | 10 +- src/design-pattern-table-per-type/README.md | 9 + .../table-per-type-impl.ts | 10 +- .../table-per-type.ts | 31 +- .../util/constructor/table-per-type.ts | 59 +-- .../util/execution/index.ts | 2 + .../util/execution/insert-and-fetch.ts | 8 +- .../util/execution/insert-row.ts | 49 ++- .../util/operation/add-parent.ts | 349 +++++------------- .../util/predicate/is-table-per-type.ts | 17 +- .../util/query/extract-all-tables.ts | 32 ++ .../util/query/extract-auto-increment.ts | 30 ++ .../util/query/extract-child-column-alias.ts | 26 ++ .../util/query/extract-column-alias.ts | 26 ++ ...t-explicit-auto-increment-value-enabled.ts | 39 ++ .../extract-insert-and-fetch-primary-key.ts | 41 ++ .../util/query/extract-parent-column-alias.ts | 25 ++ .../util/query/index.ts | 7 + .../update-and-fetch-one-by-candidate-key.ts | 4 +- .../update-and-fetch-one-by-primary-key.ts | 4 +- .../update-and-fetch-one-by-super-key.ts | 4 +- src/insert-select/insert-select-row.ts | 4 +- src/insert/insert-row.ts | 10 +- src/update/assignment-map.ts | 8 +- .../table-per-type-util/app-key-example.d.ts | 6 +- .../insert-and-fetch-row/app-key-example.d.ts | 62 ++++ ...all-table-with-column-must-be-mutable.d.ts | 26 +- ...ll-table-with-column-must-be-nullable.d.ts | 51 ++- .../insert-and-fetch-row/app-key-example.ts | 11 + .../all-table-with-column-must-be-mutable.ts | 9 +- .../all-table-with-column-must-be-nullable.ts | 12 +- 34 files changed, 603 insertions(+), 436 deletions(-) create mode 100644 src/design-pattern-table-per-type/util/query/extract-all-tables.ts create mode 100644 src/design-pattern-table-per-type/util/query/extract-auto-increment.ts create mode 100644 src/design-pattern-table-per-type/util/query/extract-child-column-alias.ts create mode 100644 src/design-pattern-table-per-type/util/query/extract-column-alias.ts create mode 100644 src/design-pattern-table-per-type/util/query/extract-explicit-auto-increment-value-enabled.ts create mode 100644 src/design-pattern-table-per-type/util/query/extract-insert-and-fetch-primary-key.ts create mode 100644 src/design-pattern-table-per-type/util/query/extract-parent-column-alias.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/app-key-example.d.ts create mode 100644 test/compile-time/input/table-per-type-util/insert-and-fetch-row/app-key-example.ts diff --git a/src/built-in-expr/built-in-expr.ts b/src/built-in-expr/built-in-expr.ts index 91120082..d99e9f1c 100644 --- a/src/built-in-expr/built-in-expr.ts +++ b/src/built-in-expr/built-in-expr.ts @@ -160,6 +160,15 @@ export type BuiltInExpr_NonCorrelated = | NonValueExpr_NonCorrelated ; +/** + * Workaround, + * https://github.com/microsoft/TypeScript/issues/35616#issuecomment-564894944 + */ +export type BuiltInExpr_NonCorrelatedOrUndefined = + | BuiltInExpr_NonCorrelated + | undefined +; + /** * We don't support subqueries because it's too complicated * to check their `IUsedRef` @@ -181,3 +190,18 @@ export type BuiltInExpr_MapCorrelated< alias : string, }> ; + +/** + * Workaround, + * https://github.com/microsoft/TypeScript/issues/35616#issuecomment-564894944 + * + * We don't support subqueries because it's too complicated + * to check their `IUsedRef` + */ +export type BuiltInExpr_MapCorrelatedOrUndefined< + ColumnMapT extends ColumnMap, + TypeT +> = + | BuiltInExpr_MapCorrelated + | undefined +; diff --git a/src/custom-expr/custom-expr.ts b/src/custom-expr/custom-expr.ts index 82b520e4..9d3e5eee 100644 --- a/src/custom-expr/custom-expr.ts +++ b/src/custom-expr/custom-expr.ts @@ -12,6 +12,15 @@ export type CustomExpr_NonCorrelated = | NonValueExpr_NonCorrelated ; +/** + * Workaround, + * https://github.com/microsoft/TypeScript/issues/35616#issuecomment-564894944 + */ +export type CustomExpr_NonCorrelatedOrUndefined = + | CustomExpr_NonCorrelated + | undefined +; + /** * We don't support subqueries because it's too complicated * to check their `IUsedRef`... For now. @@ -33,3 +42,18 @@ export type CustomExpr_MapCorrelated< alias : string, }> ; + +/** + * Workaround, + * https://github.com/microsoft/TypeScript/issues/35616#issuecomment-564894944 + * + * We don't support subqueries because it's too complicated + * to check their `IUsedRef`... For now. + */ +export type CustomExpr_MapCorrelatedOrUndefined< + ColumnMapT extends ColumnMap, + TypeT +> = + | CustomExpr_MapCorrelated + | undefined +; diff --git a/src/design-pattern-log/util/execution/track-or-insert.ts b/src/design-pattern-log/util/execution/track-or-insert.ts index 1d6be94b..64a80e2e 100644 --- a/src/design-pattern-log/util/execution/track-or-insert.ts +++ b/src/design-pattern-log/util/execution/track-or-insert.ts @@ -2,7 +2,7 @@ import {ILog} from "../../log"; import {IsolableInsertOneConnection} from "../../../execution"; import {PrimaryKey_Input} from "../../../primary-key"; import {TableUtil} from "../../../table"; -import {CustomExpr_NonCorrelated} from "../../../custom-expr"; +import {CustomExpr_NonCorrelated, CustomExpr_NonCorrelatedOrUndefined} from "../../../custom-expr"; import {Track, unsafeTrack} from "./unsafe-track"; export type TrackOrInsertRow = @@ -15,7 +15,9 @@ export type TrackOrInsertRow = */ & { readonly [columnAlias in LogT["trackedWithDefaultValue"][number]]? : ( - CustomExpr_NonCorrelated> + CustomExpr_NonCorrelatedOrUndefined< + TableUtil.ColumnType + > ) } /** @@ -50,7 +52,9 @@ export type TrackOrInsertRow = LogT["doNotCopy"][number], TableUtil.OptionalColumnAlias >]? : ( - CustomExpr_NonCorrelated> + CustomExpr_NonCorrelatedOrUndefined< + TableUtil.ColumnType + > ) } ; diff --git a/src/design-pattern-log/util/execution/unsafe-track.ts b/src/design-pattern-log/util/execution/unsafe-track.ts index c8eca844..51b0f820 100644 --- a/src/design-pattern-log/util/execution/unsafe-track.ts +++ b/src/design-pattern-log/util/execution/unsafe-track.ts @@ -2,7 +2,7 @@ import {ILog} from "../../log"; import {IsolableInsertOneConnection, ExecutionUtil, SelectConnection} from "../../../execution"; import {PrimaryKey_Input} from "../../../primary-key"; import {TableUtil} from "../../../table"; -import {CustomExpr_NonCorrelated} from "../../../custom-expr"; +import {CustomExpr_NonCorrelated, CustomExpr_NonCorrelatedOrUndefined} from "../../../custom-expr"; import {fetchLatestOrDefault} from "./fetch-latest-or-default"; import {DefaultRow} from "./fetch-default"; import {escapeIdentifierWithDoubleQuotes} from "../../../sqlstring"; @@ -21,7 +21,9 @@ export type TrackRow = */ & { readonly [columnAlias in LogT["trackedWithDefaultValue"][number]]? : ( - CustomExpr_NonCorrelated> + CustomExpr_NonCorrelatedOrUndefined< + TableUtil.ColumnType + > ) } /** @@ -67,7 +69,9 @@ export type TrackRow = LogT["doNotCopy"][number], TableUtil.OptionalColumnAlias >]? : ( - CustomExpr_NonCorrelated> + CustomExpr_NonCorrelatedOrUndefined< + TableUtil.ColumnType + > ) } ; diff --git a/src/design-pattern-table-per-type/README.md b/src/design-pattern-table-per-type/README.md index ebe931ed..84091b7c 100644 --- a/src/design-pattern-table-per-type/README.md +++ b/src/design-pattern-table-per-type/README.md @@ -14,6 +14,15 @@ Adds table-per-type inheritance. + Abstract vs Concrete + Incomplete vs Complete +----- + +### Unsoundness + ++ This utility is unsound! + + It is possible for `insertAndFetch()` to fail during run-time, + if your inheritance hierarchy does not make sense to the library. + + ----- ### Notes diff --git a/src/design-pattern-table-per-type/table-per-type-impl.ts b/src/design-pattern-table-per-type/table-per-type-impl.ts index fccd5c57..26b35c38 100644 --- a/src/design-pattern-table-per-type/table-per-type-impl.ts +++ b/src/design-pattern-table-per-type/table-per-type-impl.ts @@ -1,6 +1,6 @@ import {ITablePerType, TablePerTypeData} from "./table-per-type"; import * as TablePerTypeUtil from "./util"; -import {ITable} from "../table"; +import {TableWithPrimaryKey} from "../table"; import {SelectConnection, ExecutionUtil} from "../execution"; import {WhereDelegate} from "../where-clause"; @@ -13,8 +13,7 @@ export class TablePerType implements ITablePerTy readonly explicitAutoIncrementValueEnabled : DataT["explicitAutoIncrementValueEnabled"]; - readonly childInsertAndFetchCandidateKeys : DataT["childInsertAndFetchCandidateKeys"]; - readonly parentInsertAndFetchCandidateKeys : DataT["parentInsertAndFetchCandidateKeys"]; + readonly insertAndFetchPrimaryKey : DataT["insertAndFetchPrimaryKey"]; readonly joins : ITablePerType["joins"]; @@ -26,14 +25,13 @@ export class TablePerType implements ITablePerTy this.parentTables = data.parentTables; this.autoIncrement = data.autoIncrement; this.explicitAutoIncrementValueEnabled = data.explicitAutoIncrementValueEnabled; - this.childInsertAndFetchCandidateKeys = data.childInsertAndFetchCandidateKeys; - this.parentInsertAndFetchCandidateKeys = data.parentInsertAndFetchCandidateKeys; + this.insertAndFetchPrimaryKey = data.insertAndFetchPrimaryKey; this.joins = joins; } addParent< - ParentTableT extends ITable|ITablePerType + ParentTableT extends TableWithPrimaryKey|ITablePerType > ( parentTable : ParentTableT ) : ( diff --git a/src/design-pattern-table-per-type/table-per-type.ts b/src/design-pattern-table-per-type/table-per-type.ts index b8f8590c..05f1c6f7 100644 --- a/src/design-pattern-table-per-type/table-per-type.ts +++ b/src/design-pattern-table-per-type/table-per-type.ts @@ -1,10 +1,10 @@ -import {ITable} from "../table"; +import {TableWithPrimaryKey} from "../table"; import {Key} from "../key"; export interface TablePerTypeData { - readonly childTable : ITable, + readonly childTable : TableWithPrimaryKey, - readonly parentTables : readonly ITable[], + readonly parentTables : readonly TableWithPrimaryKey[], readonly autoIncrement : readonly string[], @@ -15,17 +15,13 @@ export interface TablePerTypeData { * * When such a `parentTable` is encountered and * we call `TablePerTypeUtil.insertAndFetch()`, - * we need to provide explicit values for at least one candidate key + * we need to provide explicit values for the primary key * of the `parentTable`. * - * A value of `undefined` indicates that we do not need - * to specify any candidate keys. - * - * A valud of `readonly never[]` indicates - * we cannot specify any candidate keys (and cannot perform `.insertAndFetch()`) + * A value of `readonly never[]` indicates + * we do not need to specify any primary key. */ - readonly childInsertAndFetchCandidateKeys : (readonly Key[])|undefined, - readonly parentInsertAndFetchCandidateKeys : (readonly Key[])|undefined, + readonly insertAndFetchPrimaryKey : Key, } export interface ITablePerType { @@ -48,8 +44,7 @@ export interface ITablePerType readonly explicitAutoIncrementValueEnabled : DataT["explicitAutoIncrementValueEnabled"]; - readonly childInsertAndFetchCandidateKeys : DataT["childInsertAndFetchCandidateKeys"]; - readonly parentInsertAndFetchCandidateKeys : DataT["parentInsertAndFetchCandidateKeys"]; + readonly insertAndFetchPrimaryKey : DataT["insertAndFetchPrimaryKey"]; /** * An array of 2-tuples containing table aliases. @@ -85,14 +80,6 @@ export type InsertableTablePerType = & ITablePerType & { childTable : { insertEnabled : true }, - parentTables : { insertEnabled : true }[], - } -; - -export type TablePerTypeWithInsertAndFetchCandidateKeys = - & ITablePerType - & { - childInsertAndFetchCandidateKeys : readonly Key[], - parentInsertAndFetchCandidateKeys : readonly Key[], + parentTables : readonly { insertEnabled : true }[], } ; diff --git a/src/design-pattern-table-per-type/util/constructor/table-per-type.ts b/src/design-pattern-table-per-type/util/constructor/table-per-type.ts index 2ef11a58..35a684b4 100644 --- a/src/design-pattern-table-per-type/util/constructor/table-per-type.ts +++ b/src/design-pattern-table-per-type/util/constructor/table-per-type.ts @@ -1,57 +1,36 @@ -import {ITable, TableUtil, TableWithAutoIncrement} from "../../../table"; +import {TableWithPrimaryKey} from "../../../table"; import {TablePerType} from "../../table-per-type-impl"; +import { + ExtractAutoIncrement, + ExtractExplicitAutoIncrementValueEnabled, + ExtractInsertAndFetchPrimaryKey, + extractAutoIncrement, + extractExplicitAutoIncrementValueEnabled, + extractInsertAndFetchPrimaryKey +} from "../query"; -export function tablePerType ( +export function tablePerType ( childTable : ChildTableT ) : TablePerType<{ childTable : ChildTableT, parentTables : readonly [], - autoIncrement : readonly Extract[], - explicitAutoIncrementValueEnabled : readonly TableUtil.ExplicitAutoIncrement[], - childInsertAndFetchCandidateKeys : ( - ChildTableT extends TableWithAutoIncrement ? - undefined : - readonly (ChildTableT["candidateKeys"][number])[] - ), - parentInsertAndFetchCandidateKeys : undefined, + autoIncrement : readonly ExtractAutoIncrement[], + explicitAutoIncrementValueEnabled : readonly ExtractExplicitAutoIncrementValueEnabled[], + insertAndFetchPrimaryKey : readonly ExtractInsertAndFetchPrimaryKey[], }> { return new TablePerType<{ childTable : ChildTableT, parentTables : readonly [], - autoIncrement : readonly Extract[], - explicitAutoIncrementValueEnabled : readonly TableUtil.ExplicitAutoIncrement[], - childInsertAndFetchCandidateKeys : ( - ChildTableT extends TableWithAutoIncrement ? - undefined : - readonly (ChildTableT["candidateKeys"][number])[] - ), - parentInsertAndFetchCandidateKeys : undefined, + autoIncrement : readonly ExtractAutoIncrement[], + explicitAutoIncrementValueEnabled : readonly ExtractExplicitAutoIncrementValueEnabled[], + insertAndFetchPrimaryKey : readonly ExtractInsertAndFetchPrimaryKey[], }>( { childTable, parentTables : [], - autoIncrement : ( - childTable.autoIncrement == undefined ? - [] : - [childTable.autoIncrement as Extract] - ), - explicitAutoIncrementValueEnabled : ( - childTable.autoIncrement == undefined ? - [] : - TableUtil.isExplicitAutoIncrement(childTable, childTable.autoIncrement) ? - [childTable.autoIncrement] : - [] - ), - childInsertAndFetchCandidateKeys : ( - childTable.autoIncrement == undefined ? - [...childTable.candidateKeys] : - undefined - ) as ( - ChildTableT extends TableWithAutoIncrement ? - undefined : - readonly (ChildTableT["candidateKeys"][number])[] - ), - parentInsertAndFetchCandidateKeys : undefined, + autoIncrement : extractAutoIncrement(childTable), + explicitAutoIncrementValueEnabled : extractExplicitAutoIncrementValueEnabled(childTable), + insertAndFetchPrimaryKey : extractInsertAndFetchPrimaryKey(childTable), }, [], ); diff --git a/src/design-pattern-table-per-type/util/execution/index.ts b/src/design-pattern-table-per-type/util/execution/index.ts index 220ffa46..142e42e9 100644 --- a/src/design-pattern-table-per-type/util/execution/index.ts +++ b/src/design-pattern-table-per-type/util/execution/index.ts @@ -1 +1,3 @@ export * from "./fetch-one"; +export * from "./insert-and-fetch"; +export * from "./insert-row"; diff --git a/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts b/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts index b629db9d..b0795c60 100644 --- a/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts +++ b/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts @@ -1,10 +1,8 @@ -import {InsertableTablePerType, TablePerTypeWithInsertAndFetchCandidateKeys} from "../../table-per-type"; -import {CustomInsertRow, CustomInsertRowWithCandidateKey} from "./insert-row"; +import {InsertableTablePerType} from "../../table-per-type"; +import {CustomInsertRowWithPrimaryKey} from "./insert-row"; export type InsertAndFetchRow< TptT extends InsertableTablePerType > = - TptT extends TablePerTypeWithInsertAndFetchCandidateKeys ? - CustomInsertRowWithCandidateKey : - CustomInsertRow + CustomInsertRowWithPrimaryKey ; diff --git a/src/design-pattern-table-per-type/util/execution/insert-row.ts b/src/design-pattern-table-per-type/util/execution/insert-row.ts index 27491a61..2f8fa536 100644 --- a/src/design-pattern-table-per-type/util/execution/insert-row.ts +++ b/src/design-pattern-table-per-type/util/execution/insert-row.ts @@ -1,8 +1,8 @@ -import {ITablePerType, TablePerTypeWithInsertAndFetchCandidateKeys} from "../../table-per-type"; +import {ITablePerType} from "../../table-per-type"; import {ColumnType, RequiredColumnAlias, OptionalColumnAlias, InsertableColumnAlias} from "../query"; import {Identity} from "../../../type-util"; -import {CustomExpr_NonCorrelated} from "../../../custom-expr"; -import {BuiltInExpr_NonCorrelated} from "../../../built-in-expr"; +import {CustomExpr_NonCorrelated, CustomExpr_NonCorrelatedOrUndefined} from "../../../custom-expr"; +import {BuiltInExpr_NonCorrelated, BuiltInExpr_NonCorrelatedOrUndefined} from "../../../built-in-expr"; import {Key, KeyUtil} from "../../../key"; export type ValueInsertRow = @@ -31,7 +31,7 @@ export type CustomInsertRow = } & { readonly [columnAlias in OptionalColumnAlias]? : ( - CustomExpr_NonCorrelated< + CustomExpr_NonCorrelatedOrUndefined< ColumnType > ) @@ -50,7 +50,7 @@ export type BuiltInInsertRow = } & { readonly [columnAlias in OptionalColumnAlias]? : ( - BuiltInExpr_NonCorrelated< + BuiltInExpr_NonCorrelatedOrUndefined< ColumnType > ) @@ -58,30 +58,30 @@ export type BuiltInInsertRow = > ; -export type CustomInsertRowWithCandidateKey_NonUnion< +export type CustomInsertRowWithPrimaryKey_NonUnion< TptT extends ITablePerType, - CandidateKeyT extends Key + PrimaryKeyT extends Key > = Identity< & { - readonly [columnAlias in Exclude, CandidateKeyT[number]>] : ( + readonly [columnAlias in Exclude, PrimaryKeyT[number]>] : ( CustomExpr_NonCorrelated< ColumnType > ) } & { - readonly [columnAlias in Exclude, CandidateKeyT[number]>]? : ( - CustomExpr_NonCorrelated< + readonly [columnAlias in Exclude, PrimaryKeyT[number]>]? : ( + CustomExpr_NonCorrelatedOrUndefined< ColumnType > ) } /** - * This Candidate key is required. + * This primary key is required. */ & { - readonly [candidateKeyColumnAlias in CandidateKeyT[number]] : ( + readonly [candidateKeyColumnAlias in PrimaryKeyT[number]] : ( CustomExpr_NonCorrelated< ColumnType > @@ -89,30 +89,23 @@ export type CustomInsertRowWithCandidateKey_NonUnion< } > ; -export type CustomInsertRowWithCandidateKeyImpl< +export type CustomInsertRowWithPrimaryKeyImpl< TptT extends ITablePerType, - CandidateKeyT extends Key + PrimaryKeyT extends Key > = - CandidateKeyT extends Key ? + PrimaryKeyT extends Key ? ( - KeyUtil.IsSubKey[]> extends true ? - CustomInsertRowWithCandidateKey_NonUnion : + KeyUtil.IsSubKey[]> extends true ? + CustomInsertRowWithPrimaryKey_NonUnion : never ) : never ; -export type CustomInsertRowWithCandidateKey< - TptT extends TablePerTypeWithInsertAndFetchCandidateKeys +export type CustomInsertRowWithPrimaryKey< + TptT extends ITablePerType > = - TptT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? - never : - TptT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? - never : - CustomInsertRowWithCandidateKeyImpl< + CustomInsertRowWithPrimaryKeyImpl< TptT, - KeyUtil.ConcatDistribute< - TptT["childInsertAndFetchCandidateKeys"][number], - TptT["parentInsertAndFetchCandidateKeys"][number] - > + TptT["insertAndFetchPrimaryKey"] > ; diff --git a/src/design-pattern-table-per-type/util/operation/add-parent.ts b/src/design-pattern-table-per-type/util/operation/add-parent.ts index 8e3d1e55..25c8fe65 100644 --- a/src/design-pattern-table-per-type/util/operation/add-parent.ts +++ b/src/design-pattern-table-per-type/util/operation/add-parent.ts @@ -1,86 +1,40 @@ import {ITablePerType} from "../../table-per-type"; -import {ITable, TableUtil, TableWithAutoIncrement} from "../../../table"; -import {ExtractParentTables, ExtractChildTable, extractParentTables, extractChildTable, ColumnAlias, columnAliases} from "../query"; +import {ITable, TableUtil, TableWithPrimaryKey} from "../../../table"; +import { + ExtractAutoIncrement, + extractAutoIncrement, + ExtractColumnAlias, + extractColumnAliases, + ExtractExplicitAutoIncrementValueEnabled, + extractExplicitAutoIncrementValueEnabled, + ExtractInsertAndFetchPrimaryKey, + extractInsertAndFetchPrimaryKey, + ExtractAllTables, + extractAllTables, +} from "../query"; import {TablePerType} from "../../table-per-type-impl"; import {removeDuplicateParents} from "./remove-duplicate-parents"; import {isTablePerType} from "../predicate"; -import {KeyUtil, Key} from "../../../key"; +import {KeyUtil} from "../../../key"; import {Identity} from "../../../type-util"; -type ExtractAutoIncrement< - T extends ITable|ITablePerType -> = - T extends ITablePerType ? - T["autoIncrement"][number] : - Extract -; - -function extractAutoIncrement< - T extends ITable|ITablePerType -> (t : T) : ExtractAutoIncrement[] { - if (isTablePerType(t)) { - return [...t.autoIncrement] as ExtractAutoIncrement[]; - } else { - return ( - t.autoIncrement == undefined ? - [] : - [t.autoIncrement] - ) as ExtractAutoIncrement[]; - } -} - -type ExtractExplicitAutoIncrementValueEnabled< - T extends ITable|ITablePerType -> = - T extends ITablePerType ? - T["explicitAutoIncrementValueEnabled"][number] : - T extends ITable ? - TableUtil.ExplicitAutoIncrement : - never -; - -function extractExplicitAutoIncrementValueEnabled< - T extends ITable|ITablePerType -> (t : T) : ExtractExplicitAutoIncrementValueEnabled[] { - if (isTablePerType(t)) { - return [...t.explicitAutoIncrementValueEnabled] as ExtractExplicitAutoIncrementValueEnabled[]; - } else if (TableUtil.isTable(t)) { - return ( - t.autoIncrement == undefined ? - [] : - //eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - t.explicitAutoIncrementValueEnabled ? - [t.autoIncrement] : - [] - ) as ExtractExplicitAutoIncrementValueEnabled[]; - } else { - throw new Error(`Expected ITable or ITablePerType`); - } -} - -type ExtractColumnAlias< - T extends ITable|ITablePerType -> = - T extends ITablePerType ? - ColumnAlias : - T extends ITable ? - TableUtil.ColumnAlias : - never -; - -function extractColumnAlias< - T extends ITable|ITablePerType -> (t : T) : ExtractColumnAlias[] { - if (isTablePerType(t)) { - return columnAliases(t) as string[] as ExtractColumnAlias[]; - } else if (TableUtil.isTable(t)) { - return TableUtil.columnAlias(t) as string[] as ExtractColumnAlias[]; - } else { - throw new Error(`Expected ITable or ITablePerType`); - } -} - -type AddParentAutoIncrement< +/** + * + `ParentT["parentTables"]` + * + `ParentT["childTable"]` + * + `Tpt["parentTables"]` + * + `Tpt["childTable"]` + * + * Before: + * ``` + * C1 -> P1 + * ``` + * + * After: + * ``` + * C1 -> P1 -> C2 -> P2 + * ``` + */ +type AddParent_AutoIncrement< TptT extends ITablePerType, ParentT extends ITable|ITablePerType > = @@ -93,23 +47,23 @@ type AddParentAutoIncrement< > ; -function addParentAutoIncrement< +function addParent_AutoIncrement< TptT extends ITablePerType, ParentT extends ITable|ITablePerType > ( tpt : TptT, parent : ParentT -) : AddParentAutoIncrement[] { - const parentColumnAliases = extractColumnAlias(parent); +) : AddParent_AutoIncrement[] { + const parentColumnAliases = extractColumnAliases(parent); return KeyUtil.removeDuplicates([ ...extractAutoIncrement(parent), ...tpt.autoIncrement.filter( columnAlias => !parentColumnAliases.includes(columnAlias as any) ), - ]) as AddParentAutoIncrement[]; + ]) as AddParent_AutoIncrement[]; } -type AddParentExplicitAutoIncrementValueEnabled< +type AddParent_ExplicitAutoIncrementValueEnabled< TptT extends ITablePerType, ParentT extends ITable|ITablePerType > = @@ -129,14 +83,14 @@ type AddParentExplicitAutoIncrementValueEnabled< > ; -function addParentExplicitAutoIncrementValueEnabled< +function addParent_ExplicitAutoIncrementValueEnabled< TptT extends ITablePerType, ParentT extends ITable|ITablePerType > ( tpt : TptT, parent : ParentT -) : AddParentExplicitAutoIncrementValueEnabled[] { - const parentColumnAliases = extractColumnAlias(parent); +) : AddParent_ExplicitAutoIncrementValueEnabled[] { + const parentColumnAliases = extractColumnAliases(parent); return KeyUtil.removeDuplicates([ ...extractExplicitAutoIncrementValueEnabled(parent).filter( @@ -148,104 +102,60 @@ function addParentExplicitAutoIncrementValueEnabled< ...tpt.explicitAutoIncrementValueEnabled.filter( columnAlias => !parentColumnAliases.includes(columnAlias as any) ), - ]) as AddParentExplicitAutoIncrementValueEnabled[]; + ]) as AddParent_ExplicitAutoIncrementValueEnabled[]; +} + +type AddParent_InsertAndFetchPrimaryKey< + TptT extends ITablePerType, + ParentT extends TableWithPrimaryKey|ITablePerType +> = + Identity< + | ExtractInsertAndFetchPrimaryKey + | Exclude< + TptT["insertAndFetchPrimaryKey"][number], + ExtractColumnAlias + > + > +; + +function addParent_InsertAndFetchPrimaryKey< + TptT extends ITablePerType, + ParentT extends TableWithPrimaryKey|ITablePerType +> ( + tpt : TptT, + parent : ParentT +) : AddParent_InsertAndFetchPrimaryKey[] { + const parentColumnAliases = extractColumnAliases(parent); + return KeyUtil.removeDuplicates([ + ...extractInsertAndFetchPrimaryKey(parent), + ...tpt.autoIncrement.filter( + columnAlias => !parentColumnAliases.includes(columnAlias as any) + ), + ]) as AddParent_InsertAndFetchPrimaryKey[]; } export type AddParent< TptT extends ITablePerType, - ParentT extends ITable|ITablePerType + ParentT extends TableWithPrimaryKey|ITablePerType > = TablePerType<{ childTable : TptT["childTable"], parentTables : readonly ( + | ExtractAllTables | TptT["parentTables"][number] - | ExtractParentTables - | ExtractChildTable )[], - autoIncrement : readonly AddParentAutoIncrement< + autoIncrement : readonly AddParent_AutoIncrement< TptT, ParentT >[], - explicitAutoIncrementValueEnabled : readonly AddParentExplicitAutoIncrementValueEnabled< + explicitAutoIncrementValueEnabled : readonly AddParent_ExplicitAutoIncrementValueEnabled< + TptT, + ParentT + >[], + insertAndFetchPrimaryKey : readonly AddParent_InsertAndFetchPrimaryKey< TptT, ParentT >[], - childInsertAndFetchCandidateKeys : ( - TptT["childInsertAndFetchCandidateKeys"] extends undefined ? - undefined : - TptT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? - readonly never[] : - TptT["childInsertAndFetchCandidateKeys"] extends readonly Key[] ? - ( - KeyUtil.SubtractDistribute< - TptT["childInsertAndFetchCandidateKeys"][number], - readonly ExtractColumnAlias[] - > extends readonly never[] ? - undefined : - readonly KeyUtil.SubtractDistribute< - TptT["childInsertAndFetchCandidateKeys"][number], - readonly ExtractColumnAlias[] - >[] - ) : - never - ), - parentInsertAndFetchCandidateKeys : ( - ParentT extends ITablePerType ? - ( - ParentT["childInsertAndFetchCandidateKeys"] extends undefined ? - ( - ParentT["parentInsertAndFetchCandidateKeys"] extends undefined ? - undefined : - ParentT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? - readonly never[] : - ParentT["parentInsertAndFetchCandidateKeys"] extends readonly Key[] ? - readonly ( - Extract< - ParentT["parentInsertAndFetchCandidateKeys"], - readonly Key[] - >[number] - )[] : - never - ) : - ParentT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? - readonly never[] : - ParentT["childInsertAndFetchCandidateKeys"] extends readonly Key[] ? - ( - ParentT["parentInsertAndFetchCandidateKeys"] extends undefined ? - readonly ( - Extract< - ParentT["childInsertAndFetchCandidateKeys"], - readonly Key[] - >[number] - )[] : - ParentT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? - readonly never[] : - ParentT["parentInsertAndFetchCandidateKeys"] extends readonly Key[] ? - readonly KeyUtil.ConcatDistribute< - KeyUtil.SubtractDistribute< - Extract< - ParentT["childInsertAndFetchCandidateKeys"], - readonly Key[] - >[number], - readonly ExtractColumnAlias[] - >, - Extract< - ParentT["parentInsertAndFetchCandidateKeys"], - readonly Key[] - >[number] - >[] : - never - ) : - never - ) : - ParentT extends ITable ? - ( - ParentT extends TableWithAutoIncrement ? - undefined : - readonly (ParentT["candidateKeys"][number])[] - ) : - never - ), }> ; @@ -263,7 +173,7 @@ export type AddParent< */ export function addParent< TptT extends ITablePerType, - ParentT extends ITable|ITablePerType + ParentT extends TableWithPrimaryKey|ITablePerType > ( tpt : TptT, parent : ParentT @@ -294,112 +204,31 @@ export function addParent< return new TablePerType<{ childTable : TptT["childTable"], parentTables : readonly ( + | ExtractAllTables | TptT["parentTables"][number] - | ExtractParentTables - | ExtractChildTable )[], - autoIncrement : readonly AddParentAutoIncrement< + autoIncrement : readonly AddParent_AutoIncrement< TptT, ParentT >[], - explicitAutoIncrementValueEnabled : readonly AddParentExplicitAutoIncrementValueEnabled< + explicitAutoIncrementValueEnabled : readonly AddParent_ExplicitAutoIncrementValueEnabled< + TptT, + ParentT + >[], + insertAndFetchPrimaryKey : readonly AddParent_InsertAndFetchPrimaryKey< TptT, ParentT >[], - childInsertAndFetchCandidateKeys : ( - TptT["childInsertAndFetchCandidateKeys"] extends undefined ? - undefined : - TptT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? - readonly never[] : - TptT["childInsertAndFetchCandidateKeys"] extends readonly Key[] ? - ( - KeyUtil.SubtractDistribute< - TptT["childInsertAndFetchCandidateKeys"][number], - readonly ExtractColumnAlias[] - > extends readonly never[] ? - undefined : - readonly KeyUtil.SubtractDistribute< - TptT["childInsertAndFetchCandidateKeys"][number], - readonly ExtractColumnAlias[] - >[] - ) : - never - ), - parentInsertAndFetchCandidateKeys : ( - ParentT extends ITablePerType ? - ( - ParentT["childInsertAndFetchCandidateKeys"] extends undefined ? - ( - ParentT["parentInsertAndFetchCandidateKeys"] extends undefined ? - undefined : - ParentT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? - readonly never[] : - ParentT["parentInsertAndFetchCandidateKeys"] extends readonly Key[] ? - readonly ( - Extract< - ParentT["parentInsertAndFetchCandidateKeys"], - readonly Key[] - >[number] - )[] : - never - ) : - ParentT["childInsertAndFetchCandidateKeys"] extends readonly never[] ? - readonly never[] : - ParentT["childInsertAndFetchCandidateKeys"] extends readonly Key[] ? - ( - ParentT["parentInsertAndFetchCandidateKeys"] extends undefined ? - readonly ( - Extract< - ParentT["childInsertAndFetchCandidateKeys"], - readonly Key[] - >[number] - )[] : - ParentT["parentInsertAndFetchCandidateKeys"] extends readonly never[] ? - readonly never[] : - ParentT["parentInsertAndFetchCandidateKeys"] extends readonly Key[] ? - readonly KeyUtil.ConcatDistribute< - KeyUtil.SubtractDistribute< - Extract< - ParentT["childInsertAndFetchCandidateKeys"], - readonly Key[] - >[number], - readonly ExtractColumnAlias[] - >, - Extract< - ParentT["parentInsertAndFetchCandidateKeys"], - readonly Key[] - >[number] - >[] : - never - ) : - never - ) : - ParentT extends ITable ? - ( - ParentT extends TableWithAutoIncrement ? - undefined : - readonly (ParentT["candidateKeys"][number])[] - ) : - never - ), }>( { childTable : tpt.childTable, parentTables : removeDuplicateParents([ + ...extractAllTables(parent), ...tpt.parentTables, - ...extractParentTables(parent), - extractChildTable(parent), ]), - autoIncrement : addParentAutoIncrement(tpt, parent), - explicitAutoIncrementValueEnabled : addParentExplicitAutoIncrementValueEnabled(tpt, parent), - /** - * @todo - */ - childInsertAndFetchCandidateKeys : null as any, - /** - * @todo - */ - parentInsertAndFetchCandidateKeys : null as any, + autoIncrement : addParent_AutoIncrement(tpt, parent), + explicitAutoIncrementValueEnabled : addParent_ExplicitAutoIncrementValueEnabled(tpt, parent), + insertAndFetchPrimaryKey : addParent_InsertAndFetchPrimaryKey(tpt, parent), }, joins ); diff --git a/src/design-pattern-table-per-type/util/predicate/is-table-per-type.ts b/src/design-pattern-table-per-type/util/predicate/is-table-per-type.ts index 9e960529..19167a5c 100644 --- a/src/design-pattern-table-per-type/util/predicate/is-table-per-type.ts +++ b/src/design-pattern-table-per-type/util/predicate/is-table-per-type.ts @@ -15,8 +15,7 @@ export function isTablePerType (mixed : unknown) : mixed is ITablePerType { "parentTables", "autoIncrement", "explicitAutoIncrementValueEnabled", - "childInsertAndFetchCandidateKeys", - "parentInsertAndFetchCandidateKeys", + "insertAndFetchPrimaryKey", "joins" ] )) { @@ -37,19 +36,9 @@ export function isTablePerType (mixed : unknown) : mixed is ITablePerType { */ (mixed.explicitAutoIncrementValueEnabled instanceof Array) && /** - * Does not check if all elements are `string[]` - */ - ( - mixed.childInsertAndFetchCandidateKeys == undefined || - (mixed.childInsertAndFetchCandidateKeys instanceof Array) - ) && - /** - * Does not check if all elements are `string[]` + * Does not check if all elements are `string` */ - ( - mixed.parentInsertAndFetchCandidateKeys == undefined || - (mixed.parentInsertAndFetchCandidateKeys instanceof Array) - ) && + (mixed.insertAndFetchPrimaryKey instanceof Array) && /** * Does not check if all elements are `string` */ diff --git a/src/design-pattern-table-per-type/util/query/extract-all-tables.ts b/src/design-pattern-table-per-type/util/query/extract-all-tables.ts new file mode 100644 index 00000000..eb1e90df --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/extract-all-tables.ts @@ -0,0 +1,32 @@ + +import {ITable, TableUtil} from "../../../table"; +import {ITablePerType} from "../../table-per-type"; +import {isTablePerType} from "../predicate"; + +export type ExtractAllTables< + T extends ITable|ITablePerType +> = + T extends ITablePerType ? + ( + | T["parentTables"][number] + | T["childTable"] + ) : + T extends ITable ? + T : + never +; + +export function extractAllTables ( + t : T +) : ExtractAllTables[] { + if (isTablePerType(t)){ + return [ + ...t.parentTables, + t.childTable, + ] as ExtractAllTables[]; + } else if (TableUtil.isTable(t)) { + return [t] as ExtractAllTables[]; + } else { + throw new Error(`Expected ITable or ITablePerType`); + } +} diff --git a/src/design-pattern-table-per-type/util/query/extract-auto-increment.ts b/src/design-pattern-table-per-type/util/query/extract-auto-increment.ts new file mode 100644 index 00000000..ceb6da76 --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/extract-auto-increment.ts @@ -0,0 +1,30 @@ + +import {ITable, TableUtil} from "../../../table"; +import {ITablePerType} from "../../table-per-type"; +import {isTablePerType} from "../predicate"; + +export type ExtractAutoIncrement< + T extends ITable|ITablePerType +> = + T extends ITablePerType ? + T["autoIncrement"][number] : + T extends ITable ? + Extract : + never +; + +export function extractAutoIncrement ( + t : T +) : ExtractAutoIncrement[] { + if (isTablePerType(t)) { + return [...t.autoIncrement] as string[] as ExtractAutoIncrement[]; + } else if (TableUtil.isTable(t)) { + return ( + t.autoIncrement == undefined ? + [] : + [t.autoIncrement] + ) as string[] as ExtractAutoIncrement[]; + } else { + throw new Error(`Expected ITable or ITablePerType`); + } +} diff --git a/src/design-pattern-table-per-type/util/query/extract-child-column-alias.ts b/src/design-pattern-table-per-type/util/query/extract-child-column-alias.ts new file mode 100644 index 00000000..8b1d33d7 --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/extract-child-column-alias.ts @@ -0,0 +1,26 @@ + +import {ITable, TableUtil} from "../../../table"; +import {ITablePerType} from "../../table-per-type"; +import {isTablePerType} from "../predicate"; + +export type ExtractChildColumnAlias< + T extends ITable|ITablePerType +> = + T extends ITablePerType ? + TableUtil.ColumnAlias : + T extends ITable ? + TableUtil.ColumnAlias : + never +; + +export function extractChildColumnAliases ( + t : T +) : ExtractChildColumnAlias[] { + if (isTablePerType(t)) { + return TableUtil.columnAlias(t.childTable) as string[] as ExtractChildColumnAlias[]; + } else if (TableUtil.isTable(t)) { + return TableUtil.columnAlias(t) as string[] as ExtractChildColumnAlias[]; + } else { + throw new Error(`Expected ITable or ITablePerType`); + } +} diff --git a/src/design-pattern-table-per-type/util/query/extract-column-alias.ts b/src/design-pattern-table-per-type/util/query/extract-column-alias.ts new file mode 100644 index 00000000..6c4df09e --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/extract-column-alias.ts @@ -0,0 +1,26 @@ +import {ITablePerType} from "../../table-per-type"; +import {ITable, TableUtil} from "../../../table"; +import {ColumnAlias, columnAliases} from "./column-alias"; +import {isTablePerType} from "../predicate"; + +export type ExtractColumnAlias< + T extends ITable|ITablePerType +> = + T extends ITablePerType ? + ColumnAlias : + T extends ITable ? + TableUtil.ColumnAlias : + never +; + +export function extractColumnAliases< + T extends ITable|ITablePerType +> (t : T) : ExtractColumnAlias[] { + if (isTablePerType(t)) { + return columnAliases(t) as string[] as ExtractColumnAlias[]; + } else if (TableUtil.isTable(t)) { + return TableUtil.columnAlias(t) as string[] as ExtractColumnAlias[]; + } else { + throw new Error(`Expected ITable or ITablePerType`); + } +} diff --git a/src/design-pattern-table-per-type/util/query/extract-explicit-auto-increment-value-enabled.ts b/src/design-pattern-table-per-type/util/query/extract-explicit-auto-increment-value-enabled.ts new file mode 100644 index 00000000..e56968bf --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/extract-explicit-auto-increment-value-enabled.ts @@ -0,0 +1,39 @@ + +import {ITable, TableUtil} from "../../../table"; +import {ITablePerType} from "../../table-per-type"; +import {isTablePerType} from "../predicate"; + +export type ExtractExplicitAutoIncrementValueEnabled< + T extends ITable|ITablePerType +> = + T extends ITablePerType ? + T["explicitAutoIncrementValueEnabled"][number] : + T extends ITable ? + ( + T["explicitAutoIncrementValueEnabled"] extends true ? + Extract : + never + ) : + never +; + +export function extractExplicitAutoIncrementValueEnabled ( + t : T +) : ExtractExplicitAutoIncrementValueEnabled[] { + if (isTablePerType(t)) { + return [...t.explicitAutoIncrementValueEnabled] as string[] as ExtractExplicitAutoIncrementValueEnabled[]; + } else if (TableUtil.isTable(t)) { + return ( + //eslint-disable-next-line @typescript-eslint/strict-boolean-expressions + t.explicitAutoIncrementValueEnabled ? + ( + t.autoIncrement == undefined ? + [] : + [t.autoIncrement] + ) : + [] + ) as string[] as ExtractExplicitAutoIncrementValueEnabled[]; + } else { + throw new Error(`Expected ITable or ITablePerType`); + } +} diff --git a/src/design-pattern-table-per-type/util/query/extract-insert-and-fetch-primary-key.ts b/src/design-pattern-table-per-type/util/query/extract-insert-and-fetch-primary-key.ts new file mode 100644 index 00000000..35ff4e24 --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/extract-insert-and-fetch-primary-key.ts @@ -0,0 +1,41 @@ + +import {TableUtil, TableWithPrimaryKey, TableWithAutoIncrement} from "../../../table"; +import {ITablePerType} from "../../table-per-type"; +import {isTablePerType} from "../predicate"; + +export type ExtractInsertAndFetchPrimaryKey< + T extends TableWithPrimaryKey|ITablePerType +> = + T extends ITablePerType ? + T["insertAndFetchPrimaryKey"][number] : + T extends TableWithAutoIncrement ? + never : + T extends TableWithPrimaryKey ? + Exclude< + T["primaryKey"][number], + | T["generatedColumns"][number] + | T["autoIncrement"] + > : + never +; + +export function extractInsertAndFetchPrimaryKey ( + t : T +) : ExtractInsertAndFetchPrimaryKey[] { + if (isTablePerType(t)) { + return [...t.insertAndFetchPrimaryKey] as string[] as ExtractInsertAndFetchPrimaryKey[]; + } else if (TableUtil.isTable(t) && t.primaryKey != undefined) { + return ( + t.autoIncrement == undefined ? + t.primaryKey.filter( + columnAlias => ( + !t.generatedColumns.includes(columnAlias) && + t.autoIncrement != columnAlias + ) + ) : + [] + ) as string[] as ExtractInsertAndFetchPrimaryKey[]; + } else { + throw new Error(`Expected TableWithPrimaryKey or ITablePerType`); + } +} diff --git a/src/design-pattern-table-per-type/util/query/extract-parent-column-alias.ts b/src/design-pattern-table-per-type/util/query/extract-parent-column-alias.ts new file mode 100644 index 00000000..62bc3aa5 --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/extract-parent-column-alias.ts @@ -0,0 +1,25 @@ + +import {ITable, TableUtil} from "../../../table"; +import {ITablePerType} from "../../table-per-type"; +import {parentColumnAliases} from "./parent-column-alias"; +import {isTablePerType} from "../predicate"; + +export type ExtractParentColumnAlias< + T extends ITable|ITablePerType +> = + T extends ITablePerType ? + TableUtil.ColumnAlias< + T["parentTables"][number] + > : + never +; + +export function extractParentColumnAliases ( + t : T +) : ExtractParentColumnAlias[] { + if (isTablePerType(t)) { + return parentColumnAliases(t) as string[] as ExtractParentColumnAlias[]; + } else { + return []; + } +} diff --git a/src/design-pattern-table-per-type/util/query/index.ts b/src/design-pattern-table-per-type/util/query/index.ts index f0f465b9..e79fd865 100644 --- a/src/design-pattern-table-per-type/util/query/index.ts +++ b/src/design-pattern-table-per-type/util/query/index.ts @@ -2,7 +2,14 @@ export * from "./column-alias"; export * from "./column-type"; export * from "./explicit-default-value-column-alias"; export * from "./extract-all-tables-with-column-alias"; +export * from "./extract-all-tables"; +export * from "./extract-auto-increment"; +export * from "./extract-explicit-auto-increment-value-enabled"; +export * from "./extract-insert-and-fetch-primary-key"; +export * from "./extract-child-column-alias"; export * from "./extract-child-table"; +export * from "./extract-column-alias"; +export * from "./extract-parent-column-alias"; export * from "./extract-parent-tables"; export * from "./extract-table-with-alias"; export * from "./find-last-join-to-table"; diff --git a/src/execution/util/operation-update/update-and-fetch-one-by-candidate-key.ts b/src/execution/util/operation-update/update-and-fetch-one-by-candidate-key.ts index fd77bae8..bed40fe6 100644 --- a/src/execution/util/operation-update/update-and-fetch-one-by-candidate-key.ts +++ b/src/execution/util/operation-update/update-and-fetch-one-by-candidate-key.ts @@ -5,7 +5,7 @@ import {CandidateKey_NonUnion, CandidateKeyUtil, CandidateKey_Input} from "../.. import {StrictUnion, AssertNonUnion, Identity} from "../../../type-util"; import {UpdateOneResult, updateOne} from "./update-one"; import {BuiltInExprUtil} from "../../../built-in-expr"; -import {CustomExpr_MapCorrelated, CustomExprUtil} from "../../../custom-expr"; +import {CustomExprUtil, CustomExpr_MapCorrelatedOrUndefined} from "../../../custom-expr"; import * as ExprLib from "../../../expr-library"; import {RowNotFoundError} from "../../../error"; @@ -46,7 +46,7 @@ export type UpdateAndFetchOneByCandidateKeyAssignmentMapImpl< Identity< & { readonly [columnAlias in TableT["mutableColumns"][number]]? : ( - CustomExpr_MapCorrelated< + CustomExpr_MapCorrelatedOrUndefined< TableT["columns"], ReturnType< TableT["columns"][columnAlias]["mapper"] diff --git a/src/execution/util/operation-update/update-and-fetch-one-by-primary-key.ts b/src/execution/util/operation-update/update-and-fetch-one-by-primary-key.ts index cd9a1644..d228f3f3 100644 --- a/src/execution/util/operation-update/update-and-fetch-one-by-primary-key.ts +++ b/src/execution/util/operation-update/update-and-fetch-one-by-primary-key.ts @@ -3,7 +3,7 @@ import {IsolableUpdateConnection, SelectConnection} from "../../connection"; import {AssignmentMapDelegate, CustomAssignmentMap} from "../../../update"; import {Identity} from "../../../type-util"; import {updateOne} from "./update-one"; -import {CustomExpr_MapCorrelated} from "../../../custom-expr"; +import {CustomExpr_MapCorrelatedOrUndefined} from "../../../custom-expr"; import * as ExprLib from "../../../expr-library"; import {PrimaryKey_Input, PrimaryKeyUtil} from "../../../primary-key"; import {UpdateAndFetchOneResult} from "./update-and-fetch-one-by-candidate-key"; @@ -16,7 +16,7 @@ export type UpdateAndFetchOneByPrimaryKeyAssignmentMapImpl< Identity< & { readonly [columnAlias in TableT["mutableColumns"][number]]? : ( - CustomExpr_MapCorrelated< + CustomExpr_MapCorrelatedOrUndefined< TableT["columns"], ReturnType< TableT["columns"][columnAlias]["mapper"] diff --git a/src/execution/util/operation-update/update-and-fetch-one-by-super-key.ts b/src/execution/util/operation-update/update-and-fetch-one-by-super-key.ts index c394db8f..b9f7e5ca 100644 --- a/src/execution/util/operation-update/update-and-fetch-one-by-super-key.ts +++ b/src/execution/util/operation-update/update-and-fetch-one-by-super-key.ts @@ -3,7 +3,7 @@ import {IsolableUpdateConnection, SelectConnection} from "../../connection"; import {AssignmentMapDelegate, CustomAssignmentMap} from "../../../update"; import {AssertNonUnion, Identity} from "../../../type-util"; import {updateOne} from "./update-one"; -import {CustomExpr_MapCorrelated} from "../../../custom-expr"; +import {CustomExpr_MapCorrelatedOrUndefined} from "../../../custom-expr"; import * as ExprLib from "../../../expr-library"; import {SuperKey_Input, SuperKeyUtil} from "../../../super-key"; import {UpdateAndFetchOneResult} from "./update-and-fetch-one-by-candidate-key"; @@ -16,7 +16,7 @@ export type UpdateAndFetchOneBySuperKeyAssignmentMapImpl< Identity< & { readonly [columnAlias in TableT["mutableColumns"][number]]? : ( - CustomExpr_MapCorrelated< + CustomExpr_MapCorrelatedOrUndefined< TableT["columns"], ReturnType< TableT["columns"][columnAlias]["mapper"] diff --git a/src/insert-select/insert-select-row.ts b/src/insert-select/insert-select-row.ts index 9d800b6e..5e7e024c 100644 --- a/src/insert-select/insert-select-row.ts +++ b/src/insert-select/insert-select-row.ts @@ -1,5 +1,5 @@ import {ITable, TableUtil} from "../table"; -import {BuiltInExpr_NonCorrelated} from "../built-in-expr"; +import {BuiltInExpr_NonCorrelated, BuiltInExpr_NonCorrelatedOrUndefined} from "../built-in-expr"; import {QueryBaseUtil} from "../query-base"; import {ColumnUtil} from "../column"; @@ -23,7 +23,7 @@ export type InsertSelectRow< } & { readonly [columnAlias in TableUtil.OptionalColumnAlias]? : ( - | BuiltInExpr_NonCorrelated< + | BuiltInExpr_NonCorrelatedOrUndefined< ReturnType > | ColumnUtil.ExtractWithType< diff --git a/src/insert/insert-row.ts b/src/insert/insert-row.ts index 1de9bb7a..3b74c3fb 100644 --- a/src/insert/insert-row.ts +++ b/src/insert/insert-row.ts @@ -1,6 +1,6 @@ import {ITable, TableUtil} from "../table"; -import {BuiltInExpr_NonCorrelated} from "../built-in-expr"; -import {CustomExpr_NonCorrelated} from "../custom-expr"; +import {BuiltInExpr_NonCorrelated, BuiltInExpr_NonCorrelatedOrUndefined} from "../built-in-expr"; +import {CustomExpr_NonCorrelated, CustomExpr_NonCorrelatedOrUndefined} from "../custom-expr"; import {Key, KeyUtil} from "../key"; import {Identity} from "../type-util"; @@ -18,7 +18,7 @@ export type CustomInsertRowWithCandidateKey_NonUnion< } & { readonly [columnAlias in Exclude, CandidateKeyT[number]>]? : ( - CustomExpr_NonCorrelated< + CustomExpr_NonCorrelatedOrUndefined< ReturnType > ) @@ -68,7 +68,7 @@ export type CustomInsertRow = } & { readonly [columnAlias in TableUtil.OptionalColumnAlias]? : ( - CustomExpr_NonCorrelated< + CustomExpr_NonCorrelatedOrUndefined< ReturnType > ) @@ -104,7 +104,7 @@ export type BuiltInInsertRow = } & { readonly [columnAlias in TableUtil.OptionalColumnAlias]? : ( - BuiltInExpr_NonCorrelated< + BuiltInExpr_NonCorrelatedOrUndefined< ReturnType > ) diff --git a/src/update/assignment-map.ts b/src/update/assignment-map.ts index 625cb30a..1b8fcd37 100644 --- a/src/update/assignment-map.ts +++ b/src/update/assignment-map.ts @@ -1,11 +1,11 @@ import {ITable, TableUtil} from "../table"; -import {BuiltInExpr_MapCorrelated} from "../built-in-expr"; -import {CustomExpr_MapCorrelated} from "../custom-expr"; +import {BuiltInExpr_MapCorrelatedOrUndefined} from "../built-in-expr"; +import {CustomExpr_MapCorrelatedOrUndefined} from "../custom-expr"; export type CustomAssignmentMap = & { readonly [columnAlias in TableT["mutableColumns"][number]]? : ( - CustomExpr_MapCorrelated< + CustomExpr_MapCorrelatedOrUndefined< TableT["columns"], ReturnType< TableT["columns"][columnAlias]["mapper"] @@ -26,7 +26,7 @@ export type CustomAssignmentMap = export type BuiltInAssignmentMap = & { readonly [columnAlias in TableT["mutableColumns"][number]]? : ( - BuiltInExpr_MapCorrelated< + BuiltInExpr_MapCorrelatedOrUndefined< TableT["columns"], ReturnType< TableT["columns"][columnAlias]["mapper"] diff --git a/test/compile-time/expected-output/table-per-type-util/app-key-example.d.ts b/test/compile-time/expected-output/table-per-type-util/app-key-example.d.ts index a694a650..54269293 100644 --- a/test/compile-time/expected-output/table-per-type-util/app-key-example.d.ts +++ b/test/compile-time/expected-output/table-per-type-util/app-key-example.d.ts @@ -207,8 +207,7 @@ export declare const browserAppKeyTpt: tsql.TablePerType<{ }>[]; autoIncrement: readonly "appKeyId"[]; explicitAutoIncrementValueEnabled: readonly never[]; - childInsertAndFetchCandidateKeys: undefined; - parentInsertAndFetchCandidateKeys: undefined; + insertAndFetchPrimaryKey: readonly never[]; }>; export declare const serverAppKeyTpt: tsql.TablePerType<{ childTable: tsql.Table<{ @@ -299,6 +298,5 @@ export declare const serverAppKeyTpt: tsql.TablePerType<{ }>[]; autoIncrement: readonly "appKeyId"[]; explicitAutoIncrementValueEnabled: readonly never[]; - childInsertAndFetchCandidateKeys: undefined; - parentInsertAndFetchCandidateKeys: undefined; + insertAndFetchPrimaryKey: readonly never[]; }>; diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/app-key-example.d.ts b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/app-key-example.d.ts new file mode 100644 index 00000000..a5dd182a --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/app-key-example.d.ts @@ -0,0 +1,62 @@ +import * as tsql from "../../../../../dist"; +export declare const browser: { + readonly key: tsql.CustomExpr_NonCorrelated; + readonly appId: tsql.CustomExpr_NonCorrelated; +} & { + readonly disabledAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly createdAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly referer?: tsql.CustomExpr_NonCorrelatedOrUndefined; +} & {}; +export declare const server: { + readonly key: tsql.CustomExpr_NonCorrelated; + readonly appId: tsql.CustomExpr_NonCorrelated; +} & { + readonly disabledAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly createdAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly ipAddress?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly trustProxy?: boolean | tsql.IExpr<{ + mapper: import("type-mapping").Mapper; + usedRef: tsql.IUsedRef<{}>; + }> | tsql.IExprSelectItem<{ + mapper: import("type-mapping").Mapper; + tableAlias: string; + alias: string; + usedRef: tsql.IUsedRef<{}>; + }> | (tsql.IQueryBase<{ + fromClause: tsql.IFromClause; + selectClause: [tsql.IColumn<{ + tableAlias: string; + columnAlias: string; + mapper: import("type-mapping").Mapper; + }> | tsql.IExprSelectItem<{ + mapper: import("type-mapping").Mapper; + tableAlias: string; + alias: string; + usedRef: tsql.IUsedRef; + }>]; + limitClause: tsql.LimitClause | undefined; + compoundQueryClause: readonly tsql.CompoundQuery[] | undefined; + compoundQueryLimitClause: tsql.LimitClause | undefined; + mapDelegate: tsql.MapDelegate | undefined; + }> & tsql.IQueryBase<{ + fromClause: tsql.IFromClause<{ + outerQueryJoins: readonly tsql.IJoin[] | undefined; + currentJoins: undefined; + }>; + selectClause: readonly (tsql.ColumnMap | tsql.IColumn | tsql.ColumnRef | tsql.IExprSelectItem)[] | undefined; + limitClause: tsql.LimitClause | undefined; + compoundQueryClause: undefined; + compoundQueryLimitClause: tsql.LimitClause | undefined; + mapDelegate: tsql.MapDelegate | undefined; + }> & tsql.IQueryBase<{ + fromClause: tsql.IFromClause<{ + outerQueryJoins: undefined; + currentJoins: readonly tsql.IJoin[] | undefined; + }>; + selectClause: readonly (tsql.ColumnMap | tsql.IColumn | tsql.ColumnRef | tsql.IExprSelectItem)[] | undefined; + limitClause: tsql.LimitClause | undefined; + compoundQueryClause: readonly tsql.CompoundQuery[] | undefined; + compoundQueryLimitClause: tsql.LimitClause | undefined; + mapDelegate: tsql.MapDelegate | undefined; + }>) | undefined; +} & {}; diff --git a/test/compile-time/expected-output/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.d.ts b/test/compile-time/expected-output/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.d.ts index b12c8472..717cc57f 100644 --- a/test/compile-time/expected-output/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.d.ts +++ b/test/compile-time/expected-output/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.d.ts @@ -13,8 +13,8 @@ export declare const bTpt: tsql.TablePerType<{ usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "x"[]; + candidateKeys: readonly (readonly "x"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -36,8 +36,8 @@ export declare const bTpt: tsql.TablePerType<{ usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "x"[]; + candidateKeys: readonly (readonly "x"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -48,8 +48,7 @@ export declare const bTpt: tsql.TablePerType<{ }>[]; autoIncrement: readonly never[]; explicitAutoIncrementValueEnabled: readonly never[]; - childInsertAndFetchCandidateKeys: readonly never[]; - parentInsertAndFetchCandidateKeys: readonly never[]; + insertAndFetchPrimaryKey: readonly "x"[]; }>; export declare const cTpt: tsql.TablePerType<{ childTable: tsql.Table<{ @@ -65,8 +64,8 @@ export declare const cTpt: tsql.TablePerType<{ usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "x"[]; + candidateKeys: readonly (readonly "x"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -88,8 +87,8 @@ export declare const cTpt: tsql.TablePerType<{ usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "x"[]; + candidateKeys: readonly (readonly "x"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -110,8 +109,8 @@ export declare const cTpt: tsql.TablePerType<{ usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "x"[]; + candidateKeys: readonly (readonly "x"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -122,8 +121,7 @@ export declare const cTpt: tsql.TablePerType<{ }>)[]; autoIncrement: readonly never[]; explicitAutoIncrementValueEnabled: readonly never[]; - childInsertAndFetchCandidateKeys: readonly never[]; - parentInsertAndFetchCandidateKeys: readonly never[]; + insertAndFetchPrimaryKey: readonly "x"[]; }>; export declare const bMutable: "x"[]; export declare const cMutable: never[]; diff --git a/test/compile-time/expected-output/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.d.ts b/test/compile-time/expected-output/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.d.ts index f5c3c99c..ac07bd67 100644 --- a/test/compile-time/expected-output/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.d.ts +++ b/test/compile-time/expected-output/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.d.ts @@ -9,12 +9,17 @@ export declare const bTpt: tsql.TablePerType<{ columnAlias: "x"; mapper: import("type-mapping").Mapper; }>; + readonly atwcmbmX: tsql.Column<{ + tableAlias: "atwcmbmB"; + columnAlias: "atwcmbmX"; + mapper: import("type-mapping").Mapper; + }>; }; usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "atwcmbmX"[]; + candidateKeys: readonly (readonly "atwcmbmX"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -32,12 +37,17 @@ export declare const bTpt: tsql.TablePerType<{ columnAlias: "x"; mapper: import("type-mapping").Mapper; }>; + readonly atwcmbmX: tsql.Column<{ + tableAlias: "atwcmbmA"; + columnAlias: "atwcmbmX"; + mapper: import("type-mapping").Mapper; + }>; }; usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "atwcmbmX"[]; + candidateKeys: readonly (readonly "atwcmbmX"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -48,8 +58,7 @@ export declare const bTpt: tsql.TablePerType<{ }>[]; autoIncrement: readonly never[]; explicitAutoIncrementValueEnabled: readonly never[]; - childInsertAndFetchCandidateKeys: readonly never[]; - parentInsertAndFetchCandidateKeys: readonly never[]; + insertAndFetchPrimaryKey: readonly "atwcmbmX"[]; }>; export declare const cTpt: tsql.TablePerType<{ childTable: tsql.Table<{ @@ -61,12 +70,17 @@ export declare const cTpt: tsql.TablePerType<{ columnAlias: "x"; mapper: import("type-mapping").Mapper; }>; + readonly atwcmbmX: tsql.Column<{ + tableAlias: "atwcmbmC"; + columnAlias: "atwcmbmX"; + mapper: import("type-mapping").Mapper; + }>; }; usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "atwcmbmX"[]; + candidateKeys: readonly (readonly "atwcmbmX"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -84,12 +98,17 @@ export declare const cTpt: tsql.TablePerType<{ columnAlias: "x"; mapper: import("type-mapping").Mapper; }>; + readonly atwcmbmX: tsql.Column<{ + tableAlias: "atwcmbmA"; + columnAlias: "atwcmbmX"; + mapper: import("type-mapping").Mapper; + }>; }; usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "atwcmbmX"[]; + candidateKeys: readonly (readonly "atwcmbmX"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -106,12 +125,17 @@ export declare const cTpt: tsql.TablePerType<{ columnAlias: "x"; mapper: import("type-mapping").Mapper; }>; + readonly atwcmbmX: tsql.Column<{ + tableAlias: "atwcmbmB"; + columnAlias: "atwcmbmX"; + mapper: import("type-mapping").Mapper; + }>; }; usedRef: tsql.IUsedRef<{}>; autoIncrement: undefined; id: undefined; - primaryKey: undefined; - candidateKeys: readonly []; + primaryKey: readonly "atwcmbmX"[]; + candidateKeys: readonly (readonly "atwcmbmX"[])[]; insertEnabled: true; deleteEnabled: true; generatedColumns: readonly []; @@ -122,8 +146,7 @@ export declare const cTpt: tsql.TablePerType<{ }>)[]; autoIncrement: readonly never[]; explicitAutoIncrementValueEnabled: readonly never[]; - childInsertAndFetchCandidateKeys: readonly never[]; - parentInsertAndFetchCandidateKeys: readonly never[]; + insertAndFetchPrimaryKey: readonly "atwcmbmX"[]; }>; export declare const bNullable: "x"[]; export declare const cNullable: never[]; diff --git a/test/compile-time/input/table-per-type-util/insert-and-fetch-row/app-key-example.ts b/test/compile-time/input/table-per-type-util/insert-and-fetch-row/app-key-example.ts new file mode 100644 index 00000000..5c7cc06a --- /dev/null +++ b/test/compile-time/input/table-per-type-util/insert-and-fetch-row/app-key-example.ts @@ -0,0 +1,11 @@ +import * as tsql from "../../../../../dist"; +import {browserAppKeyTpt, serverAppKeyTpt} from "../app-key-example"; + +declare function insertAndFetchRow (t : T) : tsql.TablePerTypeUtil.InsertAndFetchRow; + +export const browser = insertAndFetchRow( + browserAppKeyTpt +); +export const server = insertAndFetchRow( + serverAppKeyTpt +); diff --git a/test/compile-time/input/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.ts b/test/compile-time/input/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.ts index b25338cb..6b704831 100644 --- a/test/compile-time/input/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.ts +++ b/test/compile-time/input/table-per-type-util/mutable-column-alias/all-table-with-column-must-be-mutable.ts @@ -4,16 +4,19 @@ const atwcmbmA = tsql.table("atwcmbmA") .addColumns({ x : tsql.dtBigIntSigned(), }) - .addMutable(columns => [columns.x]); + .addMutable(columns => [columns.x]) + .setPrimaryKey(columns => [columns.x]); const atwcmbmB = tsql.table("atwcmbmB") .addColumns({ x : tsql.dtBigIntSigned(), }) - .addMutable(columns => [columns.x]); + .addMutable(columns => [columns.x]) + .setPrimaryKey(columns => [columns.x]); const atwcmbmC = tsql.table("atwcmbmC") .addColumns({ x : tsql.dtBigIntSigned(), - }); + }) + .setPrimaryKey(columns => [columns.x]); //.addMutable(columns => [columns.x]); export const bTpt = tsql.tablePerType(atwcmbmB) diff --git a/test/compile-time/input/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.ts b/test/compile-time/input/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.ts index 5a637be7..81623e92 100644 --- a/test/compile-time/input/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.ts +++ b/test/compile-time/input/table-per-type-util/nullable-column-alias/all-table-with-column-must-be-nullable.ts @@ -2,19 +2,25 @@ import * as tsql from "../../../../../dist"; const atwcmbmA = tsql.table("atwcmbmA") .addColumns({ + atwcmbmX : tsql.dtBigIntSigned(), x : tsql.dtBigIntSigned().orNull(), }) - .addMutable(columns => [columns.x]); + .addMutable(columns => [columns.x]) + .setPrimaryKey(columns => [columns.atwcmbmX]); const atwcmbmB = tsql.table("atwcmbmB") .addColumns({ + atwcmbmX : tsql.dtBigIntSigned(), x : tsql.dtBigIntSigned().orNull(), }) - .addMutable(columns => [columns.x]); + .addMutable(columns => [columns.x]) + .setPrimaryKey(columns => [columns.atwcmbmX]); const atwcmbmC = tsql.table("atwcmbmC") .addColumns({ + atwcmbmX : tsql.dtBigIntSigned(), x : tsql.dtBigIntSigned(), }) - .addMutable(columns => [columns.x]); + .addMutable(columns => [columns.x]) + .setPrimaryKey(columns => [columns.atwcmbmX]); export const bTpt = tsql.tablePerType(atwcmbmB) .addParent(atwcmbmA); From 3e8c7ecd48c3d55df37edd79d002cb0f182b17dd Mon Sep 17 00:00:00 2001 From: anyhowstep <5655961+AnyhowStep@users.noreply.github.com> Date: Thu, 12 Dec 2019 11:53:52 -0500 Subject: [PATCH 3/6] Reordered JOINs of TablePerTypeUitl.addParent(); matches parentTables --- .../util/operation/add-parent.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/design-pattern-table-per-type/util/operation/add-parent.ts b/src/design-pattern-table-per-type/util/operation/add-parent.ts index 25c8fe65..9c03f1b2 100644 --- a/src/design-pattern-table-per-type/util/operation/add-parent.ts +++ b/src/design-pattern-table-per-type/util/operation/add-parent.ts @@ -183,20 +183,20 @@ export function addParent< let joins : ITablePerType["joins"] | undefined = undefined; if (TableUtil.isTable(parent)) { joins = [ - ...tpt.joins, [ tpt.childTable.alias, parent.alias, ], + ...tpt.joins, ]; } else if (isTablePerType(parent)) { joins = [ - ...tpt.joins, ...parent.joins, [ tpt.childTable.alias, parent.childTable.alias, ], + ...tpt.joins, ]; } else { throw new Error(`Expected ITable or ITablePerType for parent`); From 90f4ee2b0859305e9d671862f6d0f13b4bb4c12b Mon Sep 17 00:00:00 2001 From: anyhowstep <5655961+AnyhowStep@users.noreply.github.com> Date: Thu, 12 Dec 2019 12:09:41 -0500 Subject: [PATCH 4/6] Added more tests --- .../card-customer-pay-in-method-example.d.ts | 138 ++++ .../table-per-type-util/diamond-example.d.ts | 460 +++++++++++ .../card-customer-pay-in-method-example.d.ts | 8 + .../insert-and-fetch-row/diamond-example.d.ts | 27 + .../insert-and-fetch-row/tree-example.d.ts | 11 + .../table-per-type-util/tree-example.d.ts | 739 ++++++++++++++++++ .../card-customer-pay-in-method-example.ts | 31 + .../table-per-type-util/diamond-example.ts | 62 ++ .../card-customer-pay-in-method-example.ts | 8 + .../insert-and-fetch-row/diamond-example.ts | 14 + .../insert-and-fetch-row/tree-example.ts | 8 + .../input/table-per-type-util/tree-example.ts | 106 +++ 12 files changed, 1612 insertions(+) create mode 100644 test/compile-time/expected-output/table-per-type-util/card-customer-pay-in-method-example.d.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/diamond-example.d.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/card-customer-pay-in-method-example.d.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/diamond-example.d.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/tree-example.d.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/tree-example.d.ts create mode 100644 test/compile-time/input/table-per-type-util/card-customer-pay-in-method-example.ts create mode 100644 test/compile-time/input/table-per-type-util/diamond-example.ts create mode 100644 test/compile-time/input/table-per-type-util/insert-and-fetch-row/card-customer-pay-in-method-example.ts create mode 100644 test/compile-time/input/table-per-type-util/insert-and-fetch-row/diamond-example.ts create mode 100644 test/compile-time/input/table-per-type-util/insert-and-fetch-row/tree-example.ts create mode 100644 test/compile-time/input/table-per-type-util/tree-example.ts diff --git a/test/compile-time/expected-output/table-per-type-util/card-customer-pay-in-method-example.d.ts b/test/compile-time/expected-output/table-per-type-util/card-customer-pay-in-method-example.d.ts new file mode 100644 index 00000000..89fe5ab0 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/card-customer-pay-in-method-example.d.ts @@ -0,0 +1,138 @@ +import * as tsql from "../../../../dist"; +export declare const customerPayInMethod: tsql.Table<{ + isLateral: false; + alias: "customerPayInMethod"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "customerPayInMethod"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly payInMethodId: tsql.Column<{ + tableAlias: "customerPayInMethod"; + columnAlias: "payInMethodId"; + mapper: import("type-mapping").Mapper; + }>; + readonly platformId: tsql.Column<{ + tableAlias: "customerPayInMethod"; + columnAlias: "platformId"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: undefined; + primaryKey: readonly ("payInMethodId" | "platformId")[]; + candidateKeys: readonly (readonly ("payInMethodId" | "platformId")[] | readonly "name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly []; + mutableColumns: readonly "name"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const cardCustomerPayInMethod: tsql.Table<{ + isLateral: false; + alias: "cardCustomerPayInMethod"; + columns: { + readonly payInMethodId: tsql.Column<{ + tableAlias: "cardCustomerPayInMethod"; + columnAlias: "payInMethodId"; + mapper: import("type-mapping").Mapper; + }>; + readonly platformId: tsql.Column<{ + tableAlias: "cardCustomerPayInMethod"; + columnAlias: "platformId"; + mapper: import("type-mapping").Mapper; + }>; + readonly sansitiveInformation: tsql.Column<{ + tableAlias: "cardCustomerPayInMethod"; + columnAlias: "sansitiveInformation"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: undefined; + primaryKey: readonly ("payInMethodId" | "platformId")[]; + candidateKeys: readonly (readonly ("payInMethodId" | "platformId")[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly []; + mutableColumns: readonly []; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const cardCustomerPayInMethodTpt: tsql.TablePerType<{ + childTable: tsql.Table<{ + isLateral: false; + alias: "cardCustomerPayInMethod"; + columns: { + readonly payInMethodId: tsql.Column<{ + tableAlias: "cardCustomerPayInMethod"; + columnAlias: "payInMethodId"; + mapper: import("type-mapping").Mapper; + }>; + readonly platformId: tsql.Column<{ + tableAlias: "cardCustomerPayInMethod"; + columnAlias: "platformId"; + mapper: import("type-mapping").Mapper; + }>; + readonly sansitiveInformation: tsql.Column<{ + tableAlias: "cardCustomerPayInMethod"; + columnAlias: "sansitiveInformation"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: undefined; + primaryKey: readonly ("payInMethodId" | "platformId")[]; + candidateKeys: readonly (readonly ("payInMethodId" | "platformId")[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly []; + mutableColumns: readonly []; + explicitAutoIncrementValueEnabled: false; + }>; + parentTables: readonly tsql.Table<{ + isLateral: false; + alias: "customerPayInMethod"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "customerPayInMethod"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly payInMethodId: tsql.Column<{ + tableAlias: "customerPayInMethod"; + columnAlias: "payInMethodId"; + mapper: import("type-mapping").Mapper; + }>; + readonly platformId: tsql.Column<{ + tableAlias: "customerPayInMethod"; + columnAlias: "platformId"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: undefined; + primaryKey: readonly ("payInMethodId" | "platformId")[]; + candidateKeys: readonly (readonly ("payInMethodId" | "platformId")[] | readonly "name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly []; + mutableColumns: readonly "name"[]; + explicitAutoIncrementValueEnabled: false; + }>[]; + autoIncrement: readonly never[]; + explicitAutoIncrementValueEnabled: readonly never[]; + insertAndFetchPrimaryKey: readonly ("payInMethodId" | "platformId")[]; +}>; diff --git a/test/compile-time/expected-output/table-per-type-util/diamond-example.d.ts b/test/compile-time/expected-output/table-per-type-util/diamond-example.d.ts new file mode 100644 index 00000000..23aca2f4 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/diamond-example.d.ts @@ -0,0 +1,460 @@ +import * as tsql from "../../../../dist"; +export declare const animal: tsql.Table<{ + isLateral: false; + alias: "animal"; + columns: { + readonly appId: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "appId"; + mapper: import("type-mapping").Mapper; + }>; + readonly name: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly createdAt: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly extinctAt: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "extinctAt"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "animalId"; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "name"[] | readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: "extinctAt"[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly ("name" | "extinctAt")[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const cat: tsql.Table<{ + isLateral: false; + alias: "cat"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "cat"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "cat"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly purrFrequency: tsql.Column<{ + tableAlias: "cat"; + columnAlias: "purrFrequency"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: "purrFrequency"[]; + explicitDefaultValueColumns: readonly "purrFrequency"[]; + mutableColumns: readonly "purrFrequency"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const dog: tsql.Table<{ + isLateral: false; + alias: "dog"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "dog"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "dog"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly barksPerMinute: tsql.Column<{ + tableAlias: "dog"; + columnAlias: "barksPerMinute"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: "barksPerMinute"[]; + explicitDefaultValueColumns: readonly []; + mutableColumns: readonly "barksPerMinute"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const catDog: tsql.Table<{ + isLateral: false; + alias: "catDog"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "catDog"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "catDog"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly barksPerMinute: tsql.Column<{ + tableAlias: "catDog"; + columnAlias: "barksPerMinute"; + mapper: import("type-mapping").Mapper; + }>; + readonly headsOnSameEndOfBody: tsql.Column<{ + tableAlias: "catDog"; + columnAlias: "headsOnSameEndOfBody"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: "barksPerMinute"[]; + explicitDefaultValueColumns: readonly []; + mutableColumns: readonly "headsOnSameEndOfBody"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const catTpt: tsql.TablePerType<{ + childTable: tsql.Table<{ + isLateral: false; + alias: "cat"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "cat"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "cat"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly purrFrequency: tsql.Column<{ + tableAlias: "cat"; + columnAlias: "purrFrequency"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: "purrFrequency"[]; + explicitDefaultValueColumns: readonly "purrFrequency"[]; + mutableColumns: readonly "purrFrequency"[]; + explicitAutoIncrementValueEnabled: false; + }>; + parentTables: readonly tsql.Table<{ + isLateral: false; + alias: "animal"; + columns: { + readonly appId: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "appId"; + mapper: import("type-mapping").Mapper; + }>; + readonly name: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly createdAt: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly extinctAt: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "extinctAt"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "animalId"; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "name"[] | readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: "extinctAt"[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly ("name" | "extinctAt")[]; + explicitAutoIncrementValueEnabled: false; + }>[]; + autoIncrement: readonly "animalId"[]; + explicitAutoIncrementValueEnabled: readonly never[]; + insertAndFetchPrimaryKey: readonly never[]; +}>; +export declare const dogTpt: tsql.TablePerType<{ + childTable: tsql.Table<{ + isLateral: false; + alias: "dog"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "dog"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "dog"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly barksPerMinute: tsql.Column<{ + tableAlias: "dog"; + columnAlias: "barksPerMinute"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: "barksPerMinute"[]; + explicitDefaultValueColumns: readonly []; + mutableColumns: readonly "barksPerMinute"[]; + explicitAutoIncrementValueEnabled: false; + }>; + parentTables: readonly tsql.Table<{ + isLateral: false; + alias: "animal"; + columns: { + readonly appId: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "appId"; + mapper: import("type-mapping").Mapper; + }>; + readonly name: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly createdAt: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly extinctAt: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "extinctAt"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "animalId"; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "name"[] | readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: "extinctAt"[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly ("name" | "extinctAt")[]; + explicitAutoIncrementValueEnabled: false; + }>[]; + autoIncrement: readonly "animalId"[]; + explicitAutoIncrementValueEnabled: readonly never[]; + insertAndFetchPrimaryKey: readonly never[]; +}>; +export declare const catDogTpt: tsql.TablePerType<{ + childTable: tsql.Table<{ + isLateral: false; + alias: "catDog"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "catDog"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "catDog"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly barksPerMinute: tsql.Column<{ + tableAlias: "catDog"; + columnAlias: "barksPerMinute"; + mapper: import("type-mapping").Mapper; + }>; + readonly headsOnSameEndOfBody: tsql.Column<{ + tableAlias: "catDog"; + columnAlias: "headsOnSameEndOfBody"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: "barksPerMinute"[]; + explicitDefaultValueColumns: readonly []; + mutableColumns: readonly "headsOnSameEndOfBody"[]; + explicitAutoIncrementValueEnabled: false; + }>; + parentTables: readonly (tsql.Table<{ + isLateral: false; + alias: "animal"; + columns: { + readonly appId: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "appId"; + mapper: import("type-mapping").Mapper; + }>; + readonly name: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly createdAt: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly extinctAt: tsql.Column<{ + tableAlias: "animal"; + columnAlias: "extinctAt"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "animalId"; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "name"[] | readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: "extinctAt"[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly ("name" | "extinctAt")[]; + explicitAutoIncrementValueEnabled: false; + }> | tsql.Table<{ + isLateral: false; + alias: "cat"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "cat"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "cat"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly purrFrequency: tsql.Column<{ + tableAlias: "cat"; + columnAlias: "purrFrequency"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: "purrFrequency"[]; + explicitDefaultValueColumns: readonly "purrFrequency"[]; + mutableColumns: readonly "purrFrequency"[]; + explicitAutoIncrementValueEnabled: false; + }> | tsql.Table<{ + isLateral: false; + alias: "dog"; + columns: { + readonly name: tsql.Column<{ + tableAlias: "dog"; + columnAlias: "name"; + mapper: import("type-mapping").Mapper; + }>; + readonly animalId: tsql.Column<{ + tableAlias: "dog"; + columnAlias: "animalId"; + mapper: import("type-mapping").Mapper; + }>; + readonly barksPerMinute: tsql.Column<{ + tableAlias: "dog"; + columnAlias: "barksPerMinute"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: "animalId"; + primaryKey: readonly "animalId"[]; + candidateKeys: readonly (readonly "animalId"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: "barksPerMinute"[]; + explicitDefaultValueColumns: readonly []; + mutableColumns: readonly "barksPerMinute"[]; + explicitAutoIncrementValueEnabled: false; + }>)[]; + autoIncrement: readonly "animalId"[]; + explicitAutoIncrementValueEnabled: readonly never[]; + insertAndFetchPrimaryKey: readonly never[]; +}>; diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/card-customer-pay-in-method-example.d.ts b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/card-customer-pay-in-method-example.d.ts new file mode 100644 index 00000000..6ce62c13 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/card-customer-pay-in-method-example.d.ts @@ -0,0 +1,8 @@ +import * as tsql from "../../../../../dist"; +export declare const cardCustomerPayInMethod: { + readonly name: tsql.CustomExpr_NonCorrelated; + readonly sansitiveInformation: tsql.CustomExpr_NonCorrelated; +} & {} & { + readonly payInMethodId: tsql.CustomExpr_NonCorrelated; + readonly platformId: tsql.CustomExpr_NonCorrelated; +}; diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/diamond-example.d.ts b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/diamond-example.d.ts new file mode 100644 index 00000000..6ed24ab4 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/diamond-example.d.ts @@ -0,0 +1,27 @@ +import * as tsql from "../../../../../dist"; +export declare const cat: { + readonly appId: tsql.CustomExpr_NonCorrelated; + readonly name: tsql.CustomExpr_NonCorrelated; +} & { + readonly createdAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly extinctAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly purrFrequency?: tsql.CustomExpr_NonCorrelatedOrUndefined; +} & {}; +export declare const dog: { + readonly appId: tsql.CustomExpr_NonCorrelated; + readonly name: tsql.CustomExpr_NonCorrelated; +} & { + readonly createdAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly extinctAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly barksPerMinute?: tsql.CustomExpr_NonCorrelatedOrUndefined; +} & {}; +export declare const catDog: { + readonly appId: tsql.CustomExpr_NonCorrelated; + readonly name: tsql.CustomExpr_NonCorrelated; + readonly headsOnSameEndOfBody: tsql.CustomExpr_NonCorrelated; +} & { + readonly createdAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly extinctAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly purrFrequency?: tsql.CustomExpr_NonCorrelatedOrUndefined; + readonly barksPerMinute?: tsql.CustomExpr_NonCorrelatedOrUndefined; +} & {}; diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/tree-example.d.ts b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/tree-example.d.ts new file mode 100644 index 00000000..7ac25e6d --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch-row/tree-example.d.ts @@ -0,0 +1,11 @@ +import * as tsql from "../../../../../dist"; +export declare const c: { + readonly a1Name: tsql.CustomExpr_NonCorrelated; + readonly a2Name: tsql.CustomExpr_NonCorrelated; + readonly a3Name: tsql.CustomExpr_NonCorrelated; + readonly a4Name: tsql.CustomExpr_NonCorrelated; + readonly b1Name: tsql.CustomExpr_NonCorrelated; + readonly b2Name: tsql.CustomExpr_NonCorrelated; +} & { + readonly createdAt?: tsql.CustomExpr_NonCorrelatedOrUndefined; +} & {}; diff --git a/test/compile-time/expected-output/table-per-type-util/tree-example.d.ts b/test/compile-time/expected-output/table-per-type-util/tree-example.d.ts new file mode 100644 index 00000000..f7047299 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/tree-example.d.ts @@ -0,0 +1,739 @@ +import * as tsql from "../../../../dist"; +export declare const a1: tsql.Table<{ + isLateral: false; + alias: "a1"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a1"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Id: tsql.Column<{ + tableAlias: "a1"; + columnAlias: "a1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Name: tsql.Column<{ + tableAlias: "a1"; + columnAlias: "a1Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a1Id"; + id: "a1Id"; + primaryKey: readonly "a1Id"[]; + candidateKeys: readonly (readonly "a1Id"[] | readonly "a1Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a1Name"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const a2: tsql.Table<{ + isLateral: false; + alias: "a2"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a2"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a2Id: tsql.Column<{ + tableAlias: "a2"; + columnAlias: "a2Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a2Name: tsql.Column<{ + tableAlias: "a2"; + columnAlias: "a2Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a2Id"; + id: "a2Id"; + primaryKey: readonly "a2Id"[]; + candidateKeys: readonly (readonly "a2Id"[] | readonly "a2Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a2Name"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const a3: tsql.Table<{ + isLateral: false; + alias: "a3"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a3"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Id: tsql.Column<{ + tableAlias: "a3"; + columnAlias: "a3Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Name: tsql.Column<{ + tableAlias: "a3"; + columnAlias: "a3Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a3Id"; + id: "a3Id"; + primaryKey: readonly "a3Id"[]; + candidateKeys: readonly (readonly "a3Id"[] | readonly "a3Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a3Name"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const a4: tsql.Table<{ + isLateral: false; + alias: "a4"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a4"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a4Id: tsql.Column<{ + tableAlias: "a4"; + columnAlias: "a4Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a4Name: tsql.Column<{ + tableAlias: "a4"; + columnAlias: "a4Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a4Id"; + id: "a4Id"; + primaryKey: readonly "a4Id"[]; + candidateKeys: readonly (readonly "a4Id"[] | readonly "a4Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a4Name"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const b1: tsql.Table<{ + isLateral: false; + alias: "b1"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Id: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "a1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Name: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "a1Name"; + mapper: import("type-mapping").Mapper; + }>; + readonly a2Id: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "a2Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b1Id: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "b1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b1Name: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "b1Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "b1Id"; + id: "b1Id"; + primaryKey: readonly "b1Id"[]; + candidateKeys: readonly (readonly "b1Id"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a1Name"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const b2: tsql.Table<{ + isLateral: false; + alias: "b2"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Id: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "a3Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a4Id: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "a4Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b2Name: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "b2Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: undefined; + primaryKey: readonly "a3Id"[]; + candidateKeys: readonly (readonly "a3Id"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "b2Name"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const c: tsql.Table<{ + isLateral: false; + alias: "c"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "c"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Id: tsql.Column<{ + tableAlias: "c"; + columnAlias: "a3Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b1Id: tsql.Column<{ + tableAlias: "c"; + columnAlias: "b1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b2Name: tsql.Column<{ + tableAlias: "c"; + columnAlias: "b2Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: undefined; + primaryKey: readonly ("a3Id" | "b1Id")[]; + candidateKeys: readonly (readonly ("a3Id" | "b1Id")[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "b2Name"[]; + explicitAutoIncrementValueEnabled: false; +}>; +export declare const b1Tpt: tsql.TablePerType<{ + childTable: tsql.Table<{ + isLateral: false; + alias: "b1"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Id: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "a1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Name: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "a1Name"; + mapper: import("type-mapping").Mapper; + }>; + readonly a2Id: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "a2Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b1Id: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "b1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b1Name: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "b1Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "b1Id"; + id: "b1Id"; + primaryKey: readonly "b1Id"[]; + candidateKeys: readonly (readonly "b1Id"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a1Name"[]; + explicitAutoIncrementValueEnabled: false; + }>; + parentTables: readonly (tsql.Table<{ + isLateral: false; + alias: "a1"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a1"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Id: tsql.Column<{ + tableAlias: "a1"; + columnAlias: "a1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Name: tsql.Column<{ + tableAlias: "a1"; + columnAlias: "a1Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a1Id"; + id: "a1Id"; + primaryKey: readonly "a1Id"[]; + candidateKeys: readonly (readonly "a1Id"[] | readonly "a1Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a1Name"[]; + explicitAutoIncrementValueEnabled: false; + }> | tsql.Table<{ + isLateral: false; + alias: "a2"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a2"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a2Id: tsql.Column<{ + tableAlias: "a2"; + columnAlias: "a2Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a2Name: tsql.Column<{ + tableAlias: "a2"; + columnAlias: "a2Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a2Id"; + id: "a2Id"; + primaryKey: readonly "a2Id"[]; + candidateKeys: readonly (readonly "a2Id"[] | readonly "a2Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a2Name"[]; + explicitAutoIncrementValueEnabled: false; + }>)[]; + autoIncrement: readonly ("a1Id" | "a2Id" | "b1Id")[]; + explicitAutoIncrementValueEnabled: readonly never[]; + insertAndFetchPrimaryKey: readonly never[]; +}>; +export declare const b2Tpt: tsql.TablePerType<{ + childTable: tsql.Table<{ + isLateral: false; + alias: "b2"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Id: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "a3Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a4Id: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "a4Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b2Name: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "b2Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: undefined; + primaryKey: readonly "a3Id"[]; + candidateKeys: readonly (readonly "a3Id"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "b2Name"[]; + explicitAutoIncrementValueEnabled: false; + }>; + parentTables: readonly (tsql.Table<{ + isLateral: false; + alias: "a3"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a3"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Id: tsql.Column<{ + tableAlias: "a3"; + columnAlias: "a3Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Name: tsql.Column<{ + tableAlias: "a3"; + columnAlias: "a3Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a3Id"; + id: "a3Id"; + primaryKey: readonly "a3Id"[]; + candidateKeys: readonly (readonly "a3Id"[] | readonly "a3Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a3Name"[]; + explicitAutoIncrementValueEnabled: false; + }> | tsql.Table<{ + isLateral: false; + alias: "a4"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a4"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a4Id: tsql.Column<{ + tableAlias: "a4"; + columnAlias: "a4Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a4Name: tsql.Column<{ + tableAlias: "a4"; + columnAlias: "a4Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a4Id"; + id: "a4Id"; + primaryKey: readonly "a4Id"[]; + candidateKeys: readonly (readonly "a4Id"[] | readonly "a4Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a4Name"[]; + explicitAutoIncrementValueEnabled: false; + }>)[]; + autoIncrement: readonly ("a3Id" | "a4Id")[]; + explicitAutoIncrementValueEnabled: readonly never[]; + insertAndFetchPrimaryKey: readonly never[]; +}>; +export declare const cTpt: tsql.TablePerType<{ + childTable: tsql.Table<{ + isLateral: false; + alias: "c"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "c"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Id: tsql.Column<{ + tableAlias: "c"; + columnAlias: "a3Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b1Id: tsql.Column<{ + tableAlias: "c"; + columnAlias: "b1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b2Name: tsql.Column<{ + tableAlias: "c"; + columnAlias: "b2Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: undefined; + primaryKey: readonly ("a3Id" | "b1Id")[]; + candidateKeys: readonly (readonly ("a3Id" | "b1Id")[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "b2Name"[]; + explicitAutoIncrementValueEnabled: false; + }>; + parentTables: readonly (tsql.Table<{ + isLateral: false; + alias: "a1"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a1"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Id: tsql.Column<{ + tableAlias: "a1"; + columnAlias: "a1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Name: tsql.Column<{ + tableAlias: "a1"; + columnAlias: "a1Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a1Id"; + id: "a1Id"; + primaryKey: readonly "a1Id"[]; + candidateKeys: readonly (readonly "a1Id"[] | readonly "a1Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a1Name"[]; + explicitAutoIncrementValueEnabled: false; + }> | tsql.Table<{ + isLateral: false; + alias: "a2"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a2"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a2Id: tsql.Column<{ + tableAlias: "a2"; + columnAlias: "a2Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a2Name: tsql.Column<{ + tableAlias: "a2"; + columnAlias: "a2Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a2Id"; + id: "a2Id"; + primaryKey: readonly "a2Id"[]; + candidateKeys: readonly (readonly "a2Id"[] | readonly "a2Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a2Name"[]; + explicitAutoIncrementValueEnabled: false; + }> | tsql.Table<{ + isLateral: false; + alias: "a3"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a3"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Id: tsql.Column<{ + tableAlias: "a3"; + columnAlias: "a3Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Name: tsql.Column<{ + tableAlias: "a3"; + columnAlias: "a3Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a3Id"; + id: "a3Id"; + primaryKey: readonly "a3Id"[]; + candidateKeys: readonly (readonly "a3Id"[] | readonly "a3Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a3Name"[]; + explicitAutoIncrementValueEnabled: false; + }> | tsql.Table<{ + isLateral: false; + alias: "a4"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "a4"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a4Id: tsql.Column<{ + tableAlias: "a4"; + columnAlias: "a4Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a4Name: tsql.Column<{ + tableAlias: "a4"; + columnAlias: "a4Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "a4Id"; + id: "a4Id"; + primaryKey: readonly "a4Id"[]; + candidateKeys: readonly (readonly "a4Id"[] | readonly "a4Name"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a4Name"[]; + explicitAutoIncrementValueEnabled: false; + }> | tsql.Table<{ + isLateral: false; + alias: "b1"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Id: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "a1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a1Name: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "a1Name"; + mapper: import("type-mapping").Mapper; + }>; + readonly a2Id: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "a2Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b1Id: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "b1Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b1Name: tsql.Column<{ + tableAlias: "b1"; + columnAlias: "b1Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: "b1Id"; + id: "b1Id"; + primaryKey: readonly "b1Id"[]; + candidateKeys: readonly (readonly "b1Id"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly never[]; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "a1Name"[]; + explicitAutoIncrementValueEnabled: false; + }> | tsql.Table<{ + isLateral: false; + alias: "b2"; + columns: { + readonly createdAt: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "createdAt"; + mapper: import("type-mapping").Mapper; + }>; + readonly a3Id: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "a3Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly a4Id: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "a4Id"; + mapper: import("type-mapping").Mapper; + }>; + readonly b2Name: tsql.Column<{ + tableAlias: "b2"; + columnAlias: "b2Name"; + mapper: import("type-mapping").Mapper; + }>; + }; + usedRef: tsql.IUsedRef<{}>; + autoIncrement: undefined; + id: undefined; + primaryKey: readonly "a3Id"[]; + candidateKeys: readonly (readonly "a3Id"[])[]; + insertEnabled: true; + deleteEnabled: true; + generatedColumns: readonly []; + nullableColumns: never[]; + explicitDefaultValueColumns: readonly "createdAt"[]; + mutableColumns: readonly "b2Name"[]; + explicitAutoIncrementValueEnabled: false; + }>)[]; + autoIncrement: readonly ("a1Id" | "a2Id" | "a3Id" | "a4Id" | "b1Id")[]; + explicitAutoIncrementValueEnabled: readonly never[]; + insertAndFetchPrimaryKey: readonly never[]; +}>; diff --git a/test/compile-time/input/table-per-type-util/card-customer-pay-in-method-example.ts b/test/compile-time/input/table-per-type-util/card-customer-pay-in-method-example.ts new file mode 100644 index 00000000..9cc582a8 --- /dev/null +++ b/test/compile-time/input/table-per-type-util/card-customer-pay-in-method-example.ts @@ -0,0 +1,31 @@ +import * as tsql from "../../../../dist"; + +export const customerPayInMethod = tsql.table("customerPayInMethod") + .addColumns({ + payInMethodId : tsql.dtBigIntSigned(), + platformId : tsql.dtBigIntSigned(), + name : tsql.dtVarChar(1, 512), + }) + .setPrimaryKey(columns => [ + columns.payInMethodId, + columns.platformId, + ]) + .addMutable(c => [ + c.name, + ]) + .addCandidateKey(c => [c.name]); + +export const cardCustomerPayInMethod = tsql.table("cardCustomerPayInMethod") + .addColumns({ + payInMethodId : tsql.dtBigIntSigned(), + platformId : tsql.dtBigIntSigned(), + sansitiveInformation : tsql.dtVarChar(1, 512), + }) + .setPrimaryKey(columns => [ + columns.payInMethodId, + columns.platformId, + ]) + .removeAllMutable(); + +export const cardCustomerPayInMethodTpt = tsql.tablePerType(cardCustomerPayInMethod) + .addParent(customerPayInMethod); diff --git a/test/compile-time/input/table-per-type-util/diamond-example.ts b/test/compile-time/input/table-per-type-util/diamond-example.ts new file mode 100644 index 00000000..e3cc8b62 --- /dev/null +++ b/test/compile-time/input/table-per-type-util/diamond-example.ts @@ -0,0 +1,62 @@ +import * as tsql from "../../../../dist"; + +export const animal = tsql.table("animal") + .addColumns({ + appId : tsql.dtBigIntSigned(), + animalId : tsql.dtBigIntSigned(), + name : tsql.dtVarChar(1, 512), + createdAt : tsql.dtDateTime(3), + extinctAt : tsql.dtDateTime(3).orNull(), + }) + .setAutoIncrement(c => c.animalId) + .addExplicitDefaultValue(c => [c.createdAt]) + .addMutable(c => [ + c.name, + c.extinctAt + ]) + .addCandidateKey(c => [c.name]); + +export const cat = tsql.table("cat") + .addColumns({ + animalId : tsql.dtBigIntSigned(), + name : tsql.dtVarChar(1, 512), + purrFrequency : tsql.dtDouble().orNull(), + }) + .setId(c => c.animalId) + .addExplicitDefaultValue(c => [c.purrFrequency]) + .addMutable(c => [ + c.purrFrequency, + ]); + +export const dog = tsql.table("dog") + .addColumns({ + animalId : tsql.dtBigIntSigned(), + name : tsql.dtVarChar(1, 512), + barksPerMinute : tsql.dtBigIntSigned().orNull(), + }) + .setId(c => c.animalId) + .addMutable(c => [ + c.barksPerMinute + ]); + +export const catDog = tsql.table("catDog") + .addColumns({ + animalId : tsql.dtBigIntSigned(), + name : tsql.dtVarChar(1, 512), + barksPerMinute : tsql.dtBigIntSigned().orNull(), + headsOnSameEndOfBody : tsql.dtBoolean(), + }) + .setId(c => c.animalId) + .addMutable(c => [ + c.headsOnSameEndOfBody + ]); + +export const catTpt = tsql.tablePerType(cat) + .addParent(animal); + +export const dogTpt = tsql.tablePerType(dog) + .addParent(animal); + +export const catDogTpt = tsql.tablePerType(catDog) + .addParent(catTpt) + .addParent(dogTpt); diff --git a/test/compile-time/input/table-per-type-util/insert-and-fetch-row/card-customer-pay-in-method-example.ts b/test/compile-time/input/table-per-type-util/insert-and-fetch-row/card-customer-pay-in-method-example.ts new file mode 100644 index 00000000..93eea47b --- /dev/null +++ b/test/compile-time/input/table-per-type-util/insert-and-fetch-row/card-customer-pay-in-method-example.ts @@ -0,0 +1,8 @@ +import * as tsql from "../../../../../dist"; +import {cardCustomerPayInMethodTpt} from "../card-customer-pay-in-method-example"; + +declare function insertAndFetchRow (t : T) : tsql.TablePerTypeUtil.InsertAndFetchRow; + +export const cardCustomerPayInMethod = insertAndFetchRow( + cardCustomerPayInMethodTpt +); diff --git a/test/compile-time/input/table-per-type-util/insert-and-fetch-row/diamond-example.ts b/test/compile-time/input/table-per-type-util/insert-and-fetch-row/diamond-example.ts new file mode 100644 index 00000000..07356574 --- /dev/null +++ b/test/compile-time/input/table-per-type-util/insert-and-fetch-row/diamond-example.ts @@ -0,0 +1,14 @@ +import * as tsql from "../../../../../dist"; +import {catTpt, dogTpt, catDogTpt} from "../diamond-example"; + +declare function insertAndFetchRow (t : T) : tsql.TablePerTypeUtil.InsertAndFetchRow; + +export const cat = insertAndFetchRow( + catTpt +); +export const dog = insertAndFetchRow( + dogTpt +); +export const catDog = insertAndFetchRow( + catDogTpt +); diff --git a/test/compile-time/input/table-per-type-util/insert-and-fetch-row/tree-example.ts b/test/compile-time/input/table-per-type-util/insert-and-fetch-row/tree-example.ts new file mode 100644 index 00000000..1da64309 --- /dev/null +++ b/test/compile-time/input/table-per-type-util/insert-and-fetch-row/tree-example.ts @@ -0,0 +1,8 @@ +import * as tsql from "../../../../../dist"; +import {cTpt} from "../tree-example"; + +declare function insertAndFetchRow (t : T) : tsql.TablePerTypeUtil.InsertAndFetchRow; + +export const c = insertAndFetchRow( + cTpt +); diff --git a/test/compile-time/input/table-per-type-util/tree-example.ts b/test/compile-time/input/table-per-type-util/tree-example.ts new file mode 100644 index 00000000..54251ecf --- /dev/null +++ b/test/compile-time/input/table-per-type-util/tree-example.ts @@ -0,0 +1,106 @@ +import * as tsql from "../../../../dist"; + +export const a1 = tsql.table("a1") + .addColumns({ + a1Id : tsql.dtBigIntSigned(), + a1Name : tsql.dtVarChar(1, 512), + createdAt : tsql.dtDateTime(3), + }) + .setAutoIncrement(c => c.a1Id) + .addExplicitDefaultValue(c => [c.createdAt]) + .addMutable(c => [ + c.a1Name, + ]) + .addCandidateKey(c => [c.a1Name]); + +export const a2 = tsql.table("a2") + .addColumns({ + a2Id : tsql.dtBigIntSigned(), + a2Name : tsql.dtVarChar(1, 512), + createdAt : tsql.dtDateTime(3), + }) + .setAutoIncrement(c => c.a2Id) + .addExplicitDefaultValue(c => [c.createdAt]) + .addMutable(c => [ + c.a2Name, + ]) + .addCandidateKey(c => [c.a2Name]); + +export const a3 = tsql.table("a3") + .addColumns({ + a3Id : tsql.dtBigIntSigned(), + a3Name : tsql.dtVarChar(1, 512), + createdAt : tsql.dtDateTime(3), + }) + .setAutoIncrement(c => c.a3Id) + .addExplicitDefaultValue(c => [c.createdAt]) + .addMutable(c => [ + c.a3Name, + ]) + .addCandidateKey(c => [c.a3Name]); + +export const a4 = tsql.table("a4") + .addColumns({ + a4Id : tsql.dtBigIntSigned(), + a4Name : tsql.dtVarChar(1, 512), + createdAt : tsql.dtDateTime(3), + }) + .setAutoIncrement(c => c.a4Id) + .addExplicitDefaultValue(c => [c.createdAt]) + .addMutable(c => [ + c.a4Name, + ]) + .addCandidateKey(c => [c.a4Name]); + +export const b1 = tsql.table("b1") + .addColumns({ + b1Id : tsql.dtBigIntSigned(), + a1Id : tsql.dtBigIntSigned(), + a2Id : tsql.dtBigIntSigned(), + a1Name : tsql.dtVarChar(1, 512), + b1Name : tsql.dtVarChar(1, 512), + createdAt : tsql.dtDateTime(3), + }) + .setAutoIncrement(c => c.b1Id) + .addExplicitDefaultValue(c => [c.createdAt]) + .addMutable(c => [ + c.a1Name, + ]); + +export const b2 = tsql.table("b2") + .addColumns({ + a3Id : tsql.dtBigIntSigned(), + a4Id : tsql.dtBigIntSigned(), + b2Name : tsql.dtVarChar(1, 512), + createdAt : tsql.dtDateTime(3), + }) + .setPrimaryKey(c => [c.a3Id]) + .addExplicitDefaultValue(c => [c.createdAt]) + .addMutable(c => [ + c.b2Name, + ]); + +export const c = tsql.table("c") + .addColumns({ + b1Id : tsql.dtBigIntSigned(), + a3Id : tsql.dtBigIntSigned(), + b2Name : tsql.dtVarChar(1, 512), + createdAt : tsql.dtDateTime(3), + }) + .setPrimaryKey(c => [c.b1Id, c.a3Id]) + .addExplicitDefaultValue(c => [c.createdAt]) + .addMutable(c => [ + c.b2Name, + ]); + +export const b1Tpt = tsql.tablePerType(b1) + .addParent(a1) + .addParent(a2); + +export const b2Tpt = tsql.tablePerType(b2) + .addParent(a3) + .addParent(a4); + +export const cTpt = tsql.tablePerType(c) + .addParent(b1Tpt) + .addParent(b2Tpt); From a1ad2a521377cdd09691640cb9bbf91fd1cb0559 Mon Sep 17 00:00:00 2001 From: anyhowstep <5655961+AnyhowStep@users.noreply.github.com> Date: Thu, 12 Dec 2019 23:54:11 -0500 Subject: [PATCH 5/6] Added TablePerTypeUtil.insertAndFetch() --- .../table-per-type-impl.ts | 33 +++- .../table-per-type.ts | 9 +- .../util/execution/insert-and-fetch.ts | 173 ++++++++++++++++++ .../find-table-with-generated-column-alias.ts | 37 ++++ .../util/query/implicit-auto-increment.ts | 10 + .../util/query/index.ts | 2 + src/execution/connection/connection.ts | 22 ++- .../connection/isolable-connection.ts | 6 + .../extract-with-generated-column-alias.ts | 11 ++ src/table/util/query/index.ts | 2 + src/table/util/query/try-get-schema-name.ts | 15 ++ src/type-util/index.ts | 1 + src/type-util/only-known-properties.ts | 17 ++ .../basic-app-key-example.d.ts | 19 ++ ...s-not-allowed-app-key-example-browser.d.ts | 5 + ...-allowed-app-key-example-browser.ts.errors | 92 ++++++++++ .../narrowing-app-key-example-browser.d.ts | 27 +++ ...equired-props-app-key-example-browser.d.ts | 12 ++ ...ed-props-app-key-example-browser.ts.errors | 50 +++++ .../insert-and-fetch/basic-app-key-example.ts | 23 +++ ...ops-not-allowed-app-key-example-browser.ts | 68 +++++++ .../narrowing-app-key-example-browser.ts | 31 ++++ .../required-props-app-key-example-browser.ts | 28 +++ .../app-key-example.ts | 2 +- .../basic-app-key-example-server.ts | 63 +++++++ .../default-value-app-key-example-server.ts | 70 +++++++ ...rrow-to-non-null-app-key-example-server.ts | 72 ++++++++ .../narrow-to-null-app-key-example-server.ts | 72 ++++++++ ...olumn-must-exist-app-key-example-server.ts | 29 +++ .../input/sql-web-worker/promise.sql.ts | 23 +++ 30 files changed, 1017 insertions(+), 7 deletions(-) create mode 100644 src/design-pattern-table-per-type/util/query/find-table-with-generated-column-alias.ts create mode 100644 src/table/util/query/extract-with-generated-column-alias.ts create mode 100644 src/table/util/query/try-get-schema-name.ts create mode 100644 src/type-util/only-known-properties.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch/basic-app-key-example.d.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.d.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.ts.errors create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch/narrowing-app-key-example-browser.d.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.d.ts create mode 100644 test/compile-time/expected-output/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.ts.errors create mode 100644 test/compile-time/input/table-per-type-util/insert-and-fetch/basic-app-key-example.ts create mode 100644 test/compile-time/input/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.ts create mode 100644 test/compile-time/input/table-per-type-util/insert-and-fetch/narrowing-app-key-example-browser.ts create mode 100644 test/compile-time/input/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.ts create mode 100644 test/run-time/input/design-pattern-table-per-type/insert-and-fetch/basic-app-key-example-server.ts create mode 100644 test/run-time/input/design-pattern-table-per-type/insert-and-fetch/default-value-app-key-example-server.ts create mode 100644 test/run-time/input/design-pattern-table-per-type/insert-and-fetch/narrow-to-non-null-app-key-example-server.ts create mode 100644 test/run-time/input/design-pattern-table-per-type/insert-and-fetch/narrow-to-null-app-key-example-server.ts create mode 100644 test/run-time/input/design-pattern-table-per-type/insert-and-fetch/required-column-must-exist-app-key-example-server.ts diff --git a/src/design-pattern-table-per-type/table-per-type-impl.ts b/src/design-pattern-table-per-type/table-per-type-impl.ts index 26b35c38..f43c4e98 100644 --- a/src/design-pattern-table-per-type/table-per-type-impl.ts +++ b/src/design-pattern-table-per-type/table-per-type-impl.ts @@ -1,8 +1,9 @@ -import {ITablePerType, TablePerTypeData} from "./table-per-type"; +import {ITablePerType, TablePerTypeData, InsertableTablePerType} from "./table-per-type"; import * as TablePerTypeUtil from "./util"; import {TableWithPrimaryKey} from "../table"; -import {SelectConnection, ExecutionUtil} from "../execution"; +import {SelectConnection, ExecutionUtil, IsolableInsertOneConnection} from "../execution"; import {WhereDelegate} from "../where-clause"; +import {OnlyKnownProperties} from "../type-util"; export class TablePerType implements ITablePerType { readonly childTable : DataT["childTable"]; @@ -50,4 +51,32 @@ export class TablePerType implements ITablePerTy whereDelegate ); } + + insertAndFetch< + RowT extends TablePerTypeUtil.InsertAndFetchRow< + Extract + > + > ( + this : Extract, + connection : IsolableInsertOneConnection, + row : OnlyKnownProperties< + RowT, + TablePerTypeUtil.InsertAndFetchRow< + Extract + > + > + ) : ( + Promise< + TablePerTypeUtil.InsertedAndFetchedRow< + Extract, + RowT + > + > + ) { + return TablePerTypeUtil.insertAndFetch( + this, + connection, + row + ); + } } diff --git a/src/design-pattern-table-per-type/table-per-type.ts b/src/design-pattern-table-per-type/table-per-type.ts index 05f1c6f7..989f2873 100644 --- a/src/design-pattern-table-per-type/table-per-type.ts +++ b/src/design-pattern-table-per-type/table-per-type.ts @@ -76,10 +76,13 @@ export interface ITablePerType )[]; } -export type InsertableTablePerType = - & ITablePerType +type InsertableTablePerTypeImpl = + & Omit & { childTable : { insertEnabled : true }, - parentTables : readonly { insertEnabled : true }[], + parentTables : readonly (TableWithPrimaryKey & { insertEnabled : true })[], } ; +export interface InsertableTablePerType extends InsertableTablePerTypeImpl { + +} diff --git a/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts b/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts index b0795c60..dee1b2e2 100644 --- a/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts +++ b/src/design-pattern-table-per-type/util/execution/insert-and-fetch.ts @@ -1,8 +1,181 @@ import {InsertableTablePerType} from "../../table-per-type"; import {CustomInsertRowWithPrimaryKey} from "./insert-row"; +import {IsolableInsertOneConnection, ExecutionUtil} from "../../../execution"; +import {Identity, OnlyKnownProperties, omitOwnEnumerable} from "../../../type-util"; +import {ColumnAlias, ColumnType, implicitAutoIncrement, generatedColumnAliases, findTableWithGeneratedColumnAlias} from "../query"; +import {CustomExprUtil} from "../../../custom-expr"; +import {DataTypeUtil} from "../../../data-type"; +import {BuiltInExprUtil} from "../../../built-in-expr"; +import {TableUtil} from "../../../table"; +import {expr} from "../../../expr"; +import {UsedRefUtil} from "../../../used-ref"; export type InsertAndFetchRow< TptT extends InsertableTablePerType > = CustomInsertRowWithPrimaryKey ; + +export type InsertedAndFetchedRow< + TptT extends InsertableTablePerType, + RowT extends InsertAndFetchRow +> = + Identity<{ + readonly [columnAlias in ColumnAlias] : ( + columnAlias extends keyof RowT ? + ( + undefined extends RowT[columnAlias] ? + ColumnType : + CustomExprUtil.TypeOf< + RowT[columnAlias] + > + ) : + ColumnType + ) + }> +; + +/** + * Assumes there are no duplicate `parentTables`. + * + * `.addParent()` should remove duplicates. + */ +export async function insertAndFetch< + TptT extends InsertableTablePerType, + RowT extends InsertAndFetchRow +> ( + tpt : TptT, + connection : IsolableInsertOneConnection, + insertRow : OnlyKnownProperties> +) : ( + Promise> +) { + return connection.transactionIfNotInOne(async (connection) : Promise> => { + const generated = generatedColumnAliases(tpt); + + const result : any = omitOwnEnumerable( + insertRow, + [ + /** + * We omit implicit auto-increment values because we do not + * want them to be set by users of the library. + */ + ...implicitAutoIncrement(tpt), + /** + * We omit generated values because users can't set them, anyway. + */ + ...generated, + ] as any + ); + + for(const columnAlias of generated) { + const table = findTableWithGeneratedColumnAlias( + tpt, + columnAlias + ); + + const sqlString = await connection.tryFetchGeneratedColumnExpression( + TableUtil.tryGetSchemaName(table), + table.alias, + columnAlias + ); + + if (sqlString == undefined) { + throw new Error(`Generated column ${table.alias}.${columnAlias} should have generation expression`); + } + + result[columnAlias] = expr( + { + mapper : table.columns[columnAlias].mapper, + usedRef : UsedRefUtil.fromColumnRef({}), + }, + /** + * This `sqlString` is not allowed to reference any columns. + * If it does, there is a very high chance that it will cause an error. + * + * @todo Find use case where we need to allow this to reference columns. + */ + sqlString + ); + } + + for(const table of [...tpt.parentTables, tpt.childTable]) { + const fetchedRow = await ExecutionUtil.insertAndFetch( + ( + /** + * We want to allow explicit auto-increment values internally, + * so that the same value is used for all tables of the same + * inheritance hierarchy. + */ + table.autoIncrement != undefined && !table.explicitAutoIncrementValueEnabled ? + { + ...table, + explicitAutoIncrementValueEnabled : true, + } : + table + ), + connection, + result as never + ); + for (const columnAlias of Object.keys(fetchedRow)) { + /** + * This is guaranteed to be a value expression. + */ + const newValue = fetchedRow[columnAlias]; + + if (Object.prototype.hasOwnProperty.call(result, columnAlias)) { + /** + * This `curValue` could be a non-value expression. + * We only want value expressions. + */ + const curValue = result[columnAlias]; + + if (BuiltInExprUtil.isAnyNonValueExpr(curValue)) { + /** + * Add this new value to the `rawInsertRow` + * so we can use it to insert rows to tables + * further down the inheritance hierarchy. + */ + result[columnAlias] = newValue; + continue; + } + + if (curValue === newValue) { + /** + * They are equal, do nothing. + */ + continue; + } + /** + * We need some custom equality checking logic + */ + if (!DataTypeUtil.isNullSafeEqual( + table.columns[columnAlias], + /** + * This may throw + */ + table.columns[columnAlias].mapper( + `${table.alias}.${columnAlias}`, + curValue + ), + newValue + )) { + /** + * @todo Custom `Error` type + */ + throw new Error(`All columns with the same name in an inheritance hierarchy must have the same value; mismatch found for ${table.alias}.${columnAlias}`); + } + } else { + /** + * Add this new value to the `rawInsertRow` + * so we can use it to insert rows to tables + * further down the inheritance hierarchy. + */ + result[columnAlias] = newValue; + } + } + } + + return result; + }); +} diff --git a/src/design-pattern-table-per-type/util/query/find-table-with-generated-column-alias.ts b/src/design-pattern-table-per-type/util/query/find-table-with-generated-column-alias.ts new file mode 100644 index 00000000..7a6e9da9 --- /dev/null +++ b/src/design-pattern-table-per-type/util/query/find-table-with-generated-column-alias.ts @@ -0,0 +1,37 @@ +import {ITablePerType} from "../../table-per-type"; +import {TableUtil} from "../../../table"; + +export type ExtractAllTablesWithGeneratedColumnAlias = + TableUtil.ExtractWithGeneratedColumnAlias< + ( + | TptT["childTable"] + | TptT["parentTables"][number] + ), + ColumnAliasT + > +; + +/** + * Goes up the inheritance hierarchy, starting from `childTable`, + * to look for a table with `columnAlias` as + */ +export function findTableWithGeneratedColumnAlias< + TptT extends ITablePerType, + ColumnAliasT extends string +> ( + tpt : TptT, + columnAlias : ColumnAliasT +) : ExtractAllTablesWithGeneratedColumnAlias { + if (tpt.childTable.generatedColumns.includes(columnAlias)) { + return tpt.childTable as ExtractAllTablesWithGeneratedColumnAlias; + } + + for (let i=tpt.parentTables.length-1; i>=0; --i) { + const parentTable = tpt.parentTables[i]; + if (parentTable.generatedColumns.includes(columnAlias)) { + return parentTable as ExtractAllTablesWithGeneratedColumnAlias; + } + } + + throw new Error(`No generated column ${columnAlias} in table-per-type hierarchy for ${tpt.childTable.alias}`); +} diff --git a/src/design-pattern-table-per-type/util/query/implicit-auto-increment.ts b/src/design-pattern-table-per-type/util/query/implicit-auto-increment.ts index 40ba347d..7d1b9f3b 100644 --- a/src/design-pattern-table-per-type/util/query/implicit-auto-increment.ts +++ b/src/design-pattern-table-per-type/util/query/implicit-auto-increment.ts @@ -6,3 +6,13 @@ export type ImplicitAutoIncrement = TptT["explicitAutoIncrementValueEnabled"][number] > ; + +export function implicitAutoIncrement< + TptT extends ITablePerType +> ( + tpt : TptT +) : ImplicitAutoIncrement[] { + return tpt.autoIncrement.filter(columnAlias => { + return !tpt.explicitAutoIncrementValueEnabled.includes(columnAlias); + }) as ImplicitAutoIncrement[]; +} diff --git a/src/design-pattern-table-per-type/util/query/index.ts b/src/design-pattern-table-per-type/util/query/index.ts index e79fd865..3c3f0313 100644 --- a/src/design-pattern-table-per-type/util/query/index.ts +++ b/src/design-pattern-table-per-type/util/query/index.ts @@ -13,7 +13,9 @@ export * from "./extract-parent-column-alias"; export * from "./extract-parent-tables"; export * from "./extract-table-with-alias"; export * from "./find-last-join-to-table"; +export * from "./find-table-with-generated-column-alias"; export * from "./generated-column-alias"; +export * from "./implicit-auto-increment"; export * from "./insertable-column-alias"; export * from "./mutable-column-alias"; export * from "./non-generated-column-alias"; diff --git a/src/execution/connection/connection.ts b/src/execution/connection/connection.ts index 3ba2f12c..df185cc7 100644 --- a/src/execution/connection/connection.ts +++ b/src/execution/connection/connection.ts @@ -282,6 +282,20 @@ export interface IConnection { * @param schemaAlias - If `undefined`, it uses the implied schema of the connection */ tryFetchSchemaMeta (schemaAlias : string|undefined) : Promise; + + /** + * + * @param schemaAlias - If `undefined`, it uses the implied schema of the connection + * @param tableAlias + * @param columnAlias + * + * @returns A SQL string that is the generated column's expression + */ + tryFetchGeneratedColumnExpression ( + schemaAlias : string|undefined, + tableAlias : string, + columnAlias : string + ) : Promise; } export interface ITransactionConnection extends IConnection { rollback () : Promise; @@ -295,7 +309,13 @@ export type RestrictedLockCallback = export interface RestrictedLockableConnection { lock ( callback : RestrictedLockCallback - ) : Promise + ) : Promise; + + tryFetchGeneratedColumnExpression ( + schemaAlias : string|undefined, + tableAlias : string, + columnAlias : string + ) : Promise; } export type RestrictedConnection = diff --git a/src/execution/connection/isolable-connection.ts b/src/execution/connection/isolable-connection.ts index 1a7ca50c..ba861c5a 100644 --- a/src/execution/connection/isolable-connection.ts +++ b/src/execution/connection/isolable-connection.ts @@ -17,6 +17,12 @@ export interface IsolableConnection { callback : IsolableLockCallback ) : Promise; + tryFetchGeneratedColumnExpression ( + schemaAlias : string|undefined, + tableAlias : string, + columnAlias : string + ) : Promise; + /** * Tells you if this connection is in a transaction. */ diff --git a/src/table/util/query/extract-with-generated-column-alias.ts b/src/table/util/query/extract-with-generated-column-alias.ts new file mode 100644 index 00000000..59aaf5b5 --- /dev/null +++ b/src/table/util/query/extract-with-generated-column-alias.ts @@ -0,0 +1,11 @@ +import {ITable} from "../../table"; + +export type ExtractWithGeneratedColumnAlias = + TableT extends ITable ? + ( + ColumnAliasT extends TableT["generatedColumns"][number] ? + TableT : + never + ) : + never +; diff --git a/src/table/util/query/index.ts b/src/table/util/query/index.ts index cd15ad2c..9c4d6efe 100644 --- a/src/table/util/query/index.ts +++ b/src/table/util/query/index.ts @@ -6,6 +6,8 @@ export * from "./extract-candidate-keys-in-common"; export * from "./extract-candidate-keys-with-column-alias-in-one-of-column-array"; export * from "./extract-candidate-keys-with-column-alias-in-table"; export * from "./extract-with-column-alias"; +export * from "./extract-with-generated-column-alias"; export * from "./insertable-column-alias"; export * from "./optional-column-alias"; export * from "./required-column-alias"; +export * from "./try-get-schema-name"; diff --git a/src/table/util/query/try-get-schema-name.ts b/src/table/util/query/try-get-schema-name.ts new file mode 100644 index 00000000..1b73139b --- /dev/null +++ b/src/table/util/query/try-get-schema-name.ts @@ -0,0 +1,15 @@ +import {ITable} from "../../table"; +import {isIdentifierNode} from "../../../ast"; + +export function tryGetSchemaName ( + table : ITable +) : string|undefined { + return ( + ( + isIdentifierNode(table.unaliasedAst) && + table.unaliasedAst.identifiers.length == 2 + ) ? + table.unaliasedAst.identifiers[0] : + undefined + ); +} diff --git a/src/type-util/index.ts b/src/type-util/index.ts index 740d9ca6..f6d5ecc6 100644 --- a/src/type-util/index.ts +++ b/src/type-util/index.ts @@ -11,6 +11,7 @@ export * from "./merge"; export * from "./no-infer"; export * from "./non-optional-partial"; export * from "./omit-own-enumerable"; +export * from "./only-known-properties"; export * from "./outersect"; export * from "./pick-multi"; export * from "./pick-own-enumerable"; diff --git a/src/type-util/only-known-properties.ts b/src/type-util/only-known-properties.ts new file mode 100644 index 00000000..a0a92037 --- /dev/null +++ b/src/type-util/only-known-properties.ts @@ -0,0 +1,17 @@ +/** + * Object literal may only specify known properties + */ +export type OnlyKnownProperties = + ConcreteT extends ConstraintT ? + ( + & ConcreteT + & { + [k in keyof ConcreteT] : ( + k extends keyof ConstraintT ? + ConstraintT[k] : + never + ) + } + ) : + never +; diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/basic-app-key-example.d.ts b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/basic-app-key-example.d.ts new file mode 100644 index 00000000..5770f476 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/basic-app-key-example.d.ts @@ -0,0 +1,19 @@ +export declare const browser: Promise<{ + readonly key: string; + readonly appId: bigint; + readonly appKeyId: bigint; + readonly disabledAt: Date; + readonly createdAt: Date; + readonly appKeyTypeId: import("../app-key-example").AppKeyTypeId.BROWSER; + readonly referer: null; +}>; +export declare const server: Promise<{ + readonly key: string; + readonly appId: bigint; + readonly appKeyId: bigint; + readonly disabledAt: null; + readonly createdAt: Date; + readonly appKeyTypeId: import("../app-key-example").AppKeyTypeId.SERVER; + readonly ipAddress: string; + readonly trustProxy: boolean; +}>; diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.d.ts b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.d.ts new file mode 100644 index 00000000..2f9a90f1 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.d.ts @@ -0,0 +1,5 @@ +export declare const e1: any; +export declare const e2: any; +export declare const e3: any; +export declare const e4: any; +export declare const e5: any; diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.ts.errors b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.ts.errors new file mode 100644 index 00000000..09eecc95 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.ts.errors @@ -0,0 +1,92 @@ +[ + { + "messageText": "Type 'null' is not assignable to type 'never'.", + "code": 2322, + "category": 1, + "length": 9, + "start": 235 + }, + { + "messageText": { + "messageText": "Argument of type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; } | { appId: bigint; key: string; referer: null; disabledAt: null; }' is not assignable to parameter of type '({ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; } & { appId: CustomExpr_NonCorrelated; key: CustomExpr_NonCorrelated; referer: CustomExpr_NonCorrelatedOrUndefined; disabledAt: CustomExpr_NonCorrelatedOrUndefined<...>; extraProp: never; }) | ({ ...; } & ...'.", + "category": 1, + "code": 2345, + "next": { + "messageText": "Type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; }' is not assignable to type '({ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; } & { appId: CustomExpr_NonCorrelated; key: CustomExpr_NonCorrelated; referer: CustomExpr_NonCorrelatedOrUndefined; disabledAt: CustomExpr_NonCorrelatedOrUndefined<...>; extraProp: never; }) | ({ ...; } & ...'.", + "category": 1, + "code": 2322, + "next": { + "messageText": "Type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; }' is not assignable to type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp?: undefined; } & { appId: CustomExpr_NonCorrelated; key: CustomExpr_NonCorrelated; referer: CustomExpr_NonCorrelatedOrUndefined; disabledAt: CustomExpr_NonCorrelatedOrUndefined<...>; extraProp?: undefined; }'.", + "category": 1, + "code": 2322, + "next": { + "messageText": "Type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; }' is not assignable to type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp?: undefined; }'.", + "category": 1, + "code": 2322, + "next": { + "messageText": "Types of property 'extraProp' are incompatible.", + "category": 1, + "code": 2326, + "next": { + "messageText": "Type 'null' is not assignable to type 'undefined'.", + "category": 1, + "code": 2322 + } + } + } + } + } + }, + "code": 2345, + "category": 1, + "length": 271, + "start": 334 + }, + { + "messageText": { + "messageText": "Argument of type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; } | { appId: bigint; key: string; referer: null; disabledAt: null; extraProp2: null; }' is not assignable to parameter of type '({ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; extraProp2?: undefined; } & { appId: CustomExpr_NonCorrelated; key: CustomExpr_NonCorrelated; referer: CustomExpr_NonCorrelatedOrUndefined<...>; disabledAt: CustomExpr_NonCorrelatedOrUndefined<...>; extraProp: never; ext...'.", + "category": 1, + "code": 2345, + "next": { + "messageText": "Type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; }' is not assignable to type '({ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; extraProp2?: undefined; } & { appId: CustomExpr_NonCorrelated; key: CustomExpr_NonCorrelated; referer: CustomExpr_NonCorrelatedOrUndefined<...>; disabledAt: CustomExpr_NonCorrelatedOrUndefined<...>; extraProp: never; ext...'.", + "category": 1, + "code": 2322, + "next": { + "messageText": "Type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; }' is not assignable to type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp2: null; extraProp?: undefined; } & { appId: CustomExpr_NonCorrelated; key: CustomExpr_NonCorrelated; referer: CustomExpr_NonCorrelatedOrUndefined<...>; disabledAt: CustomExpr_NonCorrelatedOrUndefined<...>; extraProp2: never; ext...'.", + "category": 1, + "code": 2322, + "next": { + "messageText": "Property 'extraProp2' is missing in type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp: null; }' but required in type '{ appId: bigint; key: string; referer: null; disabledAt: null; extraProp2: null; extraProp?: undefined; }'.", + "category": 1, + "code": 2741 + } + } + } + }, + "code": 2345, + "category": 1, + "length": 298, + "start": 681 + }, + { + "messageText": "Type 'null' is not assignable to type 'never'.", + "code": 2322, + "category": 1, + "length": 9, + "start": 1164 + }, + { + "messageText": "Type 'null' is not assignable to type 'never'.", + "code": 2322, + "category": 1, + "length": 10, + "start": 1190 + }, + { + "messageText": "Type 'bigint' is not assignable to type 'never'.", + "code": 2322, + "category": 1, + "length": 8, + "start": 1300 + } +] \ No newline at end of file diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/narrowing-app-key-example-browser.d.ts b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/narrowing-app-key-example-browser.d.ts new file mode 100644 index 00000000..fd2b592c --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/narrowing-app-key-example-browser.d.ts @@ -0,0 +1,27 @@ +export declare const narrowToNull: Promise<{ + readonly key: string; + readonly appId: bigint; + readonly appKeyId: bigint; + readonly disabledAt: null; + readonly createdAt: Date; + readonly appKeyTypeId: import("../app-key-example").AppKeyTypeId.BROWSER; + readonly referer: null; +}>; +export declare const narrowToNonNull: Promise<{ + readonly key: string; + readonly appId: bigint; + readonly appKeyId: bigint; + readonly disabledAt: Date; + readonly createdAt: Date; + readonly appKeyTypeId: import("../app-key-example").AppKeyTypeId.BROWSER; + readonly referer: string; +}>; +export declare const narrowToLiteral: Promise<{ + readonly key: "key"; + readonly appId: bigint; + readonly appKeyId: bigint; + readonly disabledAt: Date; + readonly createdAt: Date; + readonly appKeyTypeId: import("../app-key-example").AppKeyTypeId.BROWSER; + readonly referer: "hi"; +}>; diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.d.ts b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.d.ts new file mode 100644 index 00000000..82589b91 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.d.ts @@ -0,0 +1,12 @@ +export declare const e1: any; +export declare const e2: any; +export declare const e3: any; +export declare const e4: Promise<{ + readonly key: string; + readonly appId: bigint; + readonly appKeyId: bigint; + readonly disabledAt: Date | null; + readonly createdAt: Date; + readonly appKeyTypeId: import("../app-key-example").AppKeyTypeId.BROWSER; + readonly referer: string | null; +}>; diff --git a/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.ts.errors b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.ts.errors new file mode 100644 index 00000000..d00b8538 --- /dev/null +++ b/test/compile-time/expected-output/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.ts.errors @@ -0,0 +1,50 @@ +[ + { + "messageText": { + "messageText": "Argument of type '{ appId: bigint; }' is not assignable to parameter of type '{ readonly key: CustomExpr_NonCorrelated; readonly appId: CustomExpr_NonCorrelated; } & { readonly disabledAt?: CustomExpr_NonCorrelatedOrUndefined; readonly createdAt?: CustomExpr_NonCorrelatedOrUndefined<...>; readonly referer?: CustomExpr_NonCorrelatedOrUndefined<...>; } & {} & { ...; }'.", + "category": 1, + "code": 2345, + "next": { + "messageText": "Property 'key' is missing in type '{ appId: bigint; }' but required in type '{ readonly key: CustomExpr_NonCorrelated; readonly appId: CustomExpr_NonCorrelated; }'.", + "category": 1, + "code": 2741 + } + }, + "code": 2345, + "category": 1, + "length": 34, + "start": 126 + }, + { + "messageText": { + "messageText": "Argument of type '{ key: string; }' is not assignable to parameter of type '{ readonly key: CustomExpr_NonCorrelated; readonly appId: CustomExpr_NonCorrelated; } & { readonly disabledAt?: CustomExpr_NonCorrelatedOrUndefined; readonly createdAt?: CustomExpr_NonCorrelatedOrUndefined<...>; readonly referer?: CustomExpr_NonCorrelatedOrUndefined<...>; } & {} & { ...; }'.", + "category": 1, + "code": 2345, + "next": { + "messageText": "Property 'appId' is missing in type '{ key: string; }' but required in type '{ readonly key: CustomExpr_NonCorrelated; readonly appId: CustomExpr_NonCorrelated; }'.", + "category": 1, + "code": 2741 + } + }, + "code": 2345, + "category": 1, + "length": 25, + "start": 237 + }, + { + "messageText": { + "messageText": "Argument of type '{}' is not assignable to parameter of type '{ readonly key: CustomExpr_NonCorrelated; readonly appId: CustomExpr_NonCorrelated; } & { readonly disabledAt?: CustomExpr_NonCorrelatedOrUndefined; readonly createdAt?: CustomExpr_NonCorrelatedOrUndefined<...>; readonly referer?: CustomExpr_NonCorrelatedOrUndefined<...>; } & {} & { ...; }'.", + "category": 1, + "code": 2345, + "next": { + "messageText": "Type '{}' is missing the following properties from type '{ readonly key: CustomExpr_NonCorrelated; readonly appId: CustomExpr_NonCorrelated; }': key, appId", + "category": 1, + "code": 2739 + } + }, + "code": 2345, + "category": 1, + "length": 2, + "start": 339 + } +] \ No newline at end of file diff --git a/test/compile-time/input/table-per-type-util/insert-and-fetch/basic-app-key-example.ts b/test/compile-time/input/table-per-type-util/insert-and-fetch/basic-app-key-example.ts new file mode 100644 index 00000000..6d22edf4 --- /dev/null +++ b/test/compile-time/input/table-per-type-util/insert-and-fetch/basic-app-key-example.ts @@ -0,0 +1,23 @@ +import * as tsql from "../../../../../dist"; +import {browserAppKeyTpt, serverAppKeyTpt} from "../app-key-example"; + +export const browser = tsql.TablePerTypeUtil.insertAndFetch( + browserAppKeyTpt, + null as any, + { + appId : BigInt(1), + key : "test", + referer : null, + disabledAt : tsql.currentTimestamp3(), + } +); + +export const server = serverAppKeyTpt.insertAndFetch( + null as any, + { + appId : BigInt(1), + key : "test", + disabledAt : null, + ipAddress : "testtest", + } +); diff --git a/test/compile-time/input/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.ts b/test/compile-time/input/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.ts new file mode 100644 index 00000000..815779b5 --- /dev/null +++ b/test/compile-time/input/table-per-type-util/insert-and-fetch/extra-props-not-allowed-app-key-example-browser.ts @@ -0,0 +1,68 @@ +import {browserAppKeyTpt} from "../app-key-example"; + +export const e1 = browserAppKeyTpt.insertAndFetch( + null as any, + { + appId : BigInt(1), + key : "key", + referer : null, + disabledAt : null, + extraProp : null, + } +); +export const e2 = browserAppKeyTpt.insertAndFetch( + null as any, + Math.random() > 0.5 ? + { + appId : BigInt(1), + key : "key", + referer : null, + disabledAt : null, + extraProp : null, + } : + { + appId : BigInt(1), + key : "key", + referer : null, + disabledAt : null, + } +); +export const e3 = browserAppKeyTpt.insertAndFetch( + null as any, + Math.random() > 0.5 ? + { + appId : BigInt(1), + key : "key", + referer : null, + disabledAt : null, + extraProp : null, + } : + { + appId : BigInt(1), + key : "key", + referer : null, + disabledAt : null, + extraProp2 : null, + } +); +export const e4 = browserAppKeyTpt.insertAndFetch( + null as any, + { + appId : BigInt(1), + key : "key", + referer : null, + disabledAt : null, + extraProp : null, + extraProp2 : null, + } +); +export const e5 = browserAppKeyTpt.insertAndFetch( + null as any, + { + appKeyId : BigInt(2), + appId : BigInt(1), + key : "key", + referer : null, + disabledAt : null, + } +); diff --git a/test/compile-time/input/table-per-type-util/insert-and-fetch/narrowing-app-key-example-browser.ts b/test/compile-time/input/table-per-type-util/insert-and-fetch/narrowing-app-key-example-browser.ts new file mode 100644 index 00000000..0e75f464 --- /dev/null +++ b/test/compile-time/input/table-per-type-util/insert-and-fetch/narrowing-app-key-example-browser.ts @@ -0,0 +1,31 @@ +import {browserAppKeyTpt} from "../app-key-example"; + +export const narrowToNull = browserAppKeyTpt.insertAndFetch( + null as any, + { + appId : BigInt(1), + key : "key", + referer : null, + disabledAt : null, + } +); + +export const narrowToNonNull = browserAppKeyTpt.insertAndFetch( + null as any, + { + appId : BigInt(1), + key : "key", + referer : "hi", + disabledAt : new Date(), + } +); + +export const narrowToLiteral = browserAppKeyTpt.insertAndFetch( + null as any, + { + appId : BigInt(1), + key : "key", + referer : "hi", + disabledAt : new Date(), + } as const +); diff --git a/test/compile-time/input/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.ts b/test/compile-time/input/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.ts new file mode 100644 index 00000000..e1cfe068 --- /dev/null +++ b/test/compile-time/input/table-per-type-util/insert-and-fetch/required-props-app-key-example-browser.ts @@ -0,0 +1,28 @@ +import {browserAppKeyTpt} from "../app-key-example"; + +export const e1 = browserAppKeyTpt.insertAndFetch( + null as any, + { + appId : BigInt(1), + } +); + +export const e2 = browserAppKeyTpt.insertAndFetch( + null as any, + { + key : "", + } +); + +export const e3 = browserAppKeyTpt.insertAndFetch( + null as any, + {} +); + +export const e4 = browserAppKeyTpt.insertAndFetch( + null as any, + { + appId : BigInt(1), + key : "", + } +); diff --git a/test/run-time/input/design-pattern-table-per-type/app-key-example.ts b/test/run-time/input/design-pattern-table-per-type/app-key-example.ts index b46f8a0f..b25f6ad1 100644 --- a/test/run-time/input/design-pattern-table-per-type/app-key-example.ts +++ b/test/run-time/input/design-pattern-table-per-type/app-key-example.ts @@ -67,7 +67,7 @@ CREATE TABLE appKey ( appKeyId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, appKeyTypeId INTEGER NOT NULL, key VARCHAR(255) NOT NULL, - createdAt DATETIME NOT NULL, + createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, disabledAt DATETIME ); diff --git a/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/basic-app-key-example-server.ts b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/basic-app-key-example-server.ts new file mode 100644 index 00000000..96c4bfcd --- /dev/null +++ b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/basic-app-key-example-server.ts @@ -0,0 +1,63 @@ +import * as tape from "tape"; +import * as tsql from "../../../../../dist"; +import {Pool} from "../../sql-web-worker/promise.sql"; +import {SqliteWorker} from "../../sql-web-worker/worker.sql"; +import {createAppKeyTableSql, serverAppKeyTpt} from "../app-key-example"; + +tape(__filename, async (t) => { + const pool = new Pool(new SqliteWorker()); + + const fetchOneResult = await pool.acquire(async (connection) => { + await connection.exec(createAppKeyTableSql); + + const insertResult = await serverAppKeyTpt.insertAndFetch( + connection, + { + appId : BigInt(1), + key : "server", + createdAt : new Date(1), + disabledAt : new Date(2), + ipAddress : "ip", + trustProxy : false, + } + ); + + t.deepEqual( + insertResult, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : "ip", + trustProxy : false, + appId: BigInt(1), + key: "server", + createdAt: new Date(1), + disabledAt: new Date(2), + } + ); + + return serverAppKeyTpt.fetchOne( + connection, + (columns) => tsql.eq( + columns.serverAppKey.appKeyId, + BigInt(1) + ) + ).orUndefined(); + }); + + t.deepEqual( + fetchOneResult, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : "ip", + trustProxy : false, + appId: BigInt(1), + key: "server", + createdAt: new Date(1), + disabledAt: new Date(2), + } + ); + + t.end(); +}); diff --git a/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/default-value-app-key-example-server.ts b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/default-value-app-key-example-server.ts new file mode 100644 index 00000000..e85c642e --- /dev/null +++ b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/default-value-app-key-example-server.ts @@ -0,0 +1,70 @@ +import * as tape from "tape"; +import * as tsql from "../../../../../dist"; +import {Pool} from "../../sql-web-worker/promise.sql"; +import {SqliteWorker} from "../../sql-web-worker/worker.sql"; +import {createAppKeyTableSql, serverAppKeyTpt} from "../app-key-example"; + +tape(__filename, async (t) => { + const pool = new Pool(new SqliteWorker()); + + const { + fetchOneResult, + createdAt, + } = await pool.acquire(async (connection) => { + await connection.exec(createAppKeyTableSql); + + const insertResult = await serverAppKeyTpt.insertAndFetch( + connection, + { + appId : BigInt(1), + key : "server", + } + ); + + t.deepEqual( + { + ...insertResult, + createdAt : undefined, + }, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : null, + trustProxy : false, + appId: BigInt(1), + key: "server", + disabledAt: null, + createdAt: undefined, + } + ); + + t.true(insertResult.createdAt instanceof Date); + + return { + fetchOneResult : await serverAppKeyTpt.fetchOne( + connection, + (columns) => tsql.eq( + columns.serverAppKey.appKeyId, + BigInt(1) + ) + ).orUndefined(), + createdAt : insertResult.createdAt, + }; + }); + + t.deepEqual( + fetchOneResult, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : null, + trustProxy : false, + appId: BigInt(1), + key: "server", + disabledAt: null, + createdAt, + } + ); + + t.end(); +}); diff --git a/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/narrow-to-non-null-app-key-example-server.ts b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/narrow-to-non-null-app-key-example-server.ts new file mode 100644 index 00000000..44604444 --- /dev/null +++ b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/narrow-to-non-null-app-key-example-server.ts @@ -0,0 +1,72 @@ +import * as tape from "tape"; +import * as tsql from "../../../../../dist"; +import {Pool} from "../../sql-web-worker/promise.sql"; +import {SqliteWorker} from "../../sql-web-worker/worker.sql"; +import {createAppKeyTableSql, serverAppKeyTpt} from "../app-key-example"; + +tape(__filename, async (t) => { + const pool = new Pool(new SqliteWorker()); + + const { + fetchOneResult, + createdAt, + } = await pool.acquire(async (connection) => { + await connection.exec(createAppKeyTableSql); + + const insertResult = await serverAppKeyTpt.insertAndFetch( + connection, + { + appId : BigInt(1), + key : "server", + ipAddress : tsql.concat("a", "b"), + disabledAt: new Date(9001), + } + ); + + t.deepEqual( + { + ...insertResult, + createdAt : undefined, + }, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : "ab", + trustProxy : false, + appId: BigInt(1), + key: "server", + disabledAt: new Date(9001), + createdAt: undefined, + } + ); + + t.true(insertResult.createdAt instanceof Date); + + return { + fetchOneResult : await serverAppKeyTpt.fetchOne( + connection, + (columns) => tsql.eq( + columns.serverAppKey.appKeyId, + BigInt(1) + ) + ).orUndefined(), + createdAt : insertResult.createdAt, + }; + }); + + t.deepEqual( + fetchOneResult, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : "ab", + trustProxy : false, + appId: BigInt(1), + key: "server", + disabledAt: new Date(9001), + createdAt, + } + ); + + t.end(); +}); diff --git a/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/narrow-to-null-app-key-example-server.ts b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/narrow-to-null-app-key-example-server.ts new file mode 100644 index 00000000..bde0a529 --- /dev/null +++ b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/narrow-to-null-app-key-example-server.ts @@ -0,0 +1,72 @@ +import * as tape from "tape"; +import * as tsql from "../../../../../dist"; +import {Pool} from "../../sql-web-worker/promise.sql"; +import {SqliteWorker} from "../../sql-web-worker/worker.sql"; +import {createAppKeyTableSql, serverAppKeyTpt} from "../app-key-example"; + +tape(__filename, async (t) => { + const pool = new Pool(new SqliteWorker()); + + const { + fetchOneResult, + createdAt, + } = await pool.acquire(async (connection) => { + await connection.exec(createAppKeyTableSql); + + const insertResult = await serverAppKeyTpt.insertAndFetch( + connection, + { + appId : BigInt(1), + key : "server", + ipAddress : null, + disabledAt: null, + } + ); + + t.deepEqual( + { + ...insertResult, + createdAt : undefined, + }, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : null, + trustProxy : false, + appId: BigInt(1), + key: "server", + disabledAt: null, + createdAt: undefined, + } + ); + + t.true(insertResult.createdAt instanceof Date); + + return { + fetchOneResult : await serverAppKeyTpt.fetchOne( + connection, + (columns) => tsql.eq( + columns.serverAppKey.appKeyId, + BigInt(1) + ) + ).orUndefined(), + createdAt : insertResult.createdAt, + }; + }); + + t.deepEqual( + fetchOneResult, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : null, + trustProxy : false, + appId: BigInt(1), + key: "server", + disabledAt: null, + createdAt, + } + ); + + t.end(); +}); diff --git a/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/required-column-must-exist-app-key-example-server.ts b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/required-column-must-exist-app-key-example-server.ts new file mode 100644 index 00000000..c227006a --- /dev/null +++ b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/required-column-must-exist-app-key-example-server.ts @@ -0,0 +1,29 @@ +import * as tape from "tape"; +import {Pool} from "../../sql-web-worker/promise.sql"; +import {SqliteWorker} from "../../sql-web-worker/worker.sql"; +import {createAppKeyTableSql, serverAppKeyTpt} from "../app-key-example"; + +tape(__filename, async (t) => { + const pool = new Pool(new SqliteWorker()); + + await pool.acquire(async (connection) => { + await connection.exec(createAppKeyTableSql); + + await serverAppKeyTpt.insertAndFetch( + connection, + { + appId : BigInt(1), + createdAt : new Date(1), + disabledAt : new Date(2), + ipAddress : "ip", + trustProxy : false, + } as any + ).then(() => { + t.fail("Should not insert"); + }).catch((err) => { + t.pass(err.message); + }); + }); + + t.end(); +}); diff --git a/test/run-time/input/sql-web-worker/promise.sql.ts b/test/run-time/input/sql-web-worker/promise.sql.ts index 4334b43c..3168f238 100644 --- a/test/run-time/input/sql-web-worker/promise.sql.ts +++ b/test/run-time/input/sql-web-worker/promise.sql.ts @@ -1247,6 +1247,29 @@ export class Connection { tables, }; } + + tryFetchGeneratedColumnExpression ( + _schemaAlias : string|undefined, + tableAlias : string, + columnAlias : string + ) : Promise { + if (columnAlias.startsWith("__GENERATED_COLUMN_HACK__")) { + /** + * This lets us test generated columns... + * Even though SQLite does not support it. + */ + return Promise.resolve( + columnAlias.replace("__GENERATED_COLUMN_HACK__", "") + ); + } + if (tableAlias == "serverAppKey" && columnAlias == "appKeyTypeId") { + return Promise.resolve("1"); + } + if (tableAlias == "browserAppKey" && columnAlias == "appKeyTypeId") { + return Promise.resolve("2"); + } + return Promise.resolve(undefined); + } } /** From a2fd75ba8c4969e2d1069c1f63a96a5396f16458 Mon Sep 17 00:00:00 2001 From: anyhowstep <5655961+AnyhowStep@users.noreply.github.com> Date: Fri, 13 Dec 2019 00:37:08 -0500 Subject: [PATCH 6/6] More tests --- ....ts => extract-child-column-alias.ts.todo} | 0 ...ts => extract-parent-column-alias.ts.todo} | 0 .../find-table-with-generated-column-alias.ts | 2 +- .../util/query/index.ts | 4 +- ...nt-value-enabled-app-key-example-server.ts | 128 ++++++++++++++++++ ...t-generated-column-alias-value-mismatch.ts | 70 ++++++++++ .../parent-generated-column-alias.ts | 93 +++++++++++++ .../input/sql-web-worker/promise.sql.ts | 3 + 8 files changed, 297 insertions(+), 3 deletions(-) rename src/design-pattern-table-per-type/util/query/{extract-child-column-alias.ts => extract-child-column-alias.ts.todo} (100%) rename src/design-pattern-table-per-type/util/query/{extract-parent-column-alias.ts => extract-parent-column-alias.ts.todo} (100%) create mode 100644 test/run-time/input/design-pattern-table-per-type/insert-and-fetch/explicit-auto-increment-value-enabled-app-key-example-server.ts create mode 100644 test/run-time/input/design-pattern-table-per-type/insert-and-fetch/parent-generated-column-alias-value-mismatch.ts create mode 100644 test/run-time/input/design-pattern-table-per-type/insert-and-fetch/parent-generated-column-alias.ts diff --git a/src/design-pattern-table-per-type/util/query/extract-child-column-alias.ts b/src/design-pattern-table-per-type/util/query/extract-child-column-alias.ts.todo similarity index 100% rename from src/design-pattern-table-per-type/util/query/extract-child-column-alias.ts rename to src/design-pattern-table-per-type/util/query/extract-child-column-alias.ts.todo diff --git a/src/design-pattern-table-per-type/util/query/extract-parent-column-alias.ts b/src/design-pattern-table-per-type/util/query/extract-parent-column-alias.ts.todo similarity index 100% rename from src/design-pattern-table-per-type/util/query/extract-parent-column-alias.ts rename to src/design-pattern-table-per-type/util/query/extract-parent-column-alias.ts.todo diff --git a/src/design-pattern-table-per-type/util/query/find-table-with-generated-column-alias.ts b/src/design-pattern-table-per-type/util/query/find-table-with-generated-column-alias.ts index 7a6e9da9..981ee1b8 100644 --- a/src/design-pattern-table-per-type/util/query/find-table-with-generated-column-alias.ts +++ b/src/design-pattern-table-per-type/util/query/find-table-with-generated-column-alias.ts @@ -13,7 +13,7 @@ export type ExtractAllTablesWithGeneratedColumnAlias { + const pool = new Pool(new SqliteWorker()); + + const fetchOneResult = await pool.acquire(async (connection) => { + await connection.exec(createAppKeyTableSql); + + const insertResult = await serverAppKeyTpt.insertAndFetch( + connection, + { + appId : BigInt(1), + appKeyId : BigInt(1337), + key : "server", + createdAt : new Date(1), + disabledAt : new Date(2), + ipAddress : "ip", + trustProxy : false, + } + ); + + t.deepEqual( + insertResult, + { + appKeyId : BigInt(1337), + appKeyTypeId: BigInt(1), + ipAddress : "ip", + trustProxy : false, + appId: BigInt(1), + key: "server", + createdAt: new Date(1), + disabledAt: new Date(2), + } + ); + + return serverAppKeyTpt.fetchOne( + connection, + (columns) => tsql.eq( + columns.serverAppKey.appKeyId, + BigInt(1337) + ) + ).orUndefined(); + }); + + t.deepEqual( + fetchOneResult, + { + appKeyId : BigInt(1337), + appKeyTypeId: BigInt(1), + ipAddress : "ip", + trustProxy : false, + appId: BigInt(1), + key: "server", + createdAt: new Date(1), + disabledAt: new Date(2), + } + ); + + t.end(); +}); + +tape(__filename, async (t) => { + const pool = new Pool(new SqliteWorker()); + + const fetchOneResult = await pool.acquire(async (connection) => { + await connection.exec(createAppKeyTableSql); + + const insertResult = await serverAppKeyTpt.insertAndFetch( + connection, + { + appId : BigInt(1), + key : "server", + createdAt : new Date(1), + disabledAt : new Date(2), + ipAddress : "ip", + trustProxy : false, + } + ); + + t.deepEqual( + insertResult, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : "ip", + trustProxy : false, + appId: BigInt(1), + key: "server", + createdAt: new Date(1), + disabledAt: new Date(2), + } + ); + + return serverAppKeyTpt.fetchOne( + connection, + (columns) => tsql.eq( + columns.serverAppKey.appKeyId, + BigInt(1) + ) + ).orUndefined(); + }); + + t.deepEqual( + fetchOneResult, + { + appKeyId: BigInt(1), + appKeyTypeId: BigInt(1), + ipAddress : "ip", + trustProxy : false, + appId: BigInt(1), + key: "server", + createdAt: new Date(1), + disabledAt: new Date(2), + } + ); + + t.end(); +}); diff --git a/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/parent-generated-column-alias-value-mismatch.ts b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/parent-generated-column-alias-value-mismatch.ts new file mode 100644 index 00000000..0bcf4c80 --- /dev/null +++ b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/parent-generated-column-alias-value-mismatch.ts @@ -0,0 +1,70 @@ +import * as tape from "tape"; +import * as tsql from "../../../../../dist"; +import {Pool} from "../../sql-web-worker/promise.sql"; +import {SqliteWorker} from "../../sql-web-worker/worker.sql"; + +const top = tsql.table("top") + .addColumns({ + appKeyId : tsql.dtBigIntSigned(), + a : tsql.dtBigIntSigned(), + b : tsql.dtBigIntSigned(), + generated : tsql.dtBigIntSigned(), + }) + .setAutoIncrement(c => c.appKeyId); + +const mid = tsql.table("mid") + .addColumns({ + appKeyId : tsql.dtBigIntSigned(), + generated : tsql.dtBigIntSigned(), + }) + .setAutoIncrement(c => c.appKeyId) + .addGenerated(columns => [columns.generated]); + +const btm = tsql.table("btm") + .addColumns({ + appKeyId : tsql.dtBigIntSigned(), + generated : tsql.dtBigIntSigned(), + }) + .setAutoIncrement(c => c.appKeyId); + +const btmTpt = tsql.tablePerType(btm) + .addParent(mid) + .addParent(top); + +tape(__filename, async (t) => { + const pool = new Pool(new SqliteWorker()); + + await pool.acquire(async (connection) => { + await connection.exec(` + CREATE TABLE top ( + appKeyId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + a INTEGER NOT NULL, + b INTEGER NOT NULL, + generated INTEGER NOT NULL + ); + CREATE TABLE mid ( + appKeyId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + -- This will cause a mismatch value error + generated INTEGER NOT NULL DEFAULT 9002 + ); + CREATE TABLE btm ( + appKeyId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + generated INTEGER NOT NULL + ); + `); + + await btmTpt.insertAndFetch( + connection, + { + a : BigInt(10), + b : tsql.integer.add(BigInt(20), BigInt(5)), + } + ).then(() => { + t.fail("9001 != 9002, should not insert"); + }).catch((err) => { + t.deepEqual(err.message, "All columns with the same name in an inheritance hierarchy must have the same value; mismatch found for mid.generated"); + }); + }); + + t.end(); +}); diff --git a/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/parent-generated-column-alias.ts b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/parent-generated-column-alias.ts new file mode 100644 index 00000000..be8000dd --- /dev/null +++ b/test/run-time/input/design-pattern-table-per-type/insert-and-fetch/parent-generated-column-alias.ts @@ -0,0 +1,93 @@ +import * as tape from "tape"; +import * as tsql from "../../../../../dist"; +import {Pool} from "../../sql-web-worker/promise.sql"; +import {SqliteWorker} from "../../sql-web-worker/worker.sql"; + +const top = tsql.table("top") + .addColumns({ + appKeyId : tsql.dtBigIntSigned(), + a : tsql.dtBigIntSigned(), + b : tsql.dtBigIntSigned(), + generated : tsql.dtBigIntSigned(), + }) + .setAutoIncrement(c => c.appKeyId); + +const mid = tsql.table("mid") + .addColumns({ + appKeyId : tsql.dtBigIntSigned(), + generated : tsql.dtBigIntSigned(), + }) + .setAutoIncrement(c => c.appKeyId) + .addGenerated(columns => [columns.generated]); + +const btm = tsql.table("btm") + .addColumns({ + appKeyId : tsql.dtBigIntSigned(), + generated : tsql.dtBigIntSigned(), + }) + .setAutoIncrement(c => c.appKeyId); + +const btmTpt = tsql.tablePerType(btm) + .addParent(mid) + .addParent(top); + +tape(__filename, async (t) => { + const pool = new Pool(new SqliteWorker()); + + const fetchOneResult = await pool.acquire(async (connection) => { + await connection.exec(` + CREATE TABLE top ( + appKeyId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + a INTEGER NOT NULL, + b INTEGER NOT NULL, + generated INTEGER NOT NULL + ); + CREATE TABLE mid ( + appKeyId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + generated INTEGER NOT NULL DEFAULT 9001 + ); + CREATE TABLE btm ( + appKeyId INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + generated INTEGER NOT NULL + ); + `); + + const insertResult = await btmTpt.insertAndFetch( + connection, + { + a : BigInt(10), + b : tsql.integer.add(BigInt(20), BigInt(5)), + } + ); + + t.deepEqual( + insertResult, + { + appKeyId : BigInt(1), + a : BigInt(10), + b : BigInt(25), + generated : BigInt(9001), + } + ); + + return btmTpt.fetchOne( + connection, + (columns) => tsql.eq( + columns.mid.appKeyId, + BigInt(1) + ) + ).orUndefined(); + }); + + t.deepEqual( + fetchOneResult, + { + appKeyId : BigInt(1), + a : BigInt(10), + b : BigInt(25), + generated : BigInt(9001), + } + ); + + t.end(); +}); diff --git a/test/run-time/input/sql-web-worker/promise.sql.ts b/test/run-time/input/sql-web-worker/promise.sql.ts index 3168f238..0862eee4 100644 --- a/test/run-time/input/sql-web-worker/promise.sql.ts +++ b/test/run-time/input/sql-web-worker/promise.sql.ts @@ -1268,6 +1268,9 @@ export class Connection { if (tableAlias == "browserAppKey" && columnAlias == "appKeyTypeId") { return Promise.resolve("2"); } + if (tableAlias == "mid" && columnAlias == "generated") { + return Promise.resolve("9001"); + } return Promise.resolve(undefined); } }