@sigitex/outlaw 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +9 -0
  3. package/package.json +52 -0
  4. package/src/api/DatabaseTable.ts +51 -0
  5. package/src/api/DatabaseView.ts +22 -0
  6. package/src/api/api.types.ts +200 -0
  7. package/src/api/createDatabase.ts +24 -0
  8. package/src/api/index.ts +4 -0
  9. package/src/bun/bun.ts +27 -0
  10. package/src/bun/index.ts +1 -0
  11. package/src/cloudflare/cloudflare.ts +18 -0
  12. package/src/cloudflare/index.ts +1 -0
  13. package/src/console.ts +14 -0
  14. package/src/cowboyMigration/Compare.ts +97 -0
  15. package/src/cowboyMigration/CowboyConnection.ts +57 -0
  16. package/src/cowboyMigration/CowboyMigrator.ts +437 -0
  17. package/src/cowboyMigration/CowboySeeder.ts +245 -0
  18. package/src/cowboyMigration/cowboyMigration.types.ts +29 -0
  19. package/src/cowboyMigration/createSchemaHacker.ts +28 -0
  20. package/src/cowboyMigration/index.ts +3 -0
  21. package/src/crypto.d.ts +9 -0
  22. package/src/framework/Format.ts +31 -0
  23. package/src/framework/definitions.d.ts +4 -0
  24. package/src/framework/index.ts +1 -0
  25. package/src/index.ts +10 -0
  26. package/src/queryBuilder/DeleteBuilder.ts +40 -0
  27. package/src/queryBuilder/InsertBuilder.ts +31 -0
  28. package/src/queryBuilder/Mappings.ts +55 -0
  29. package/src/queryBuilder/SelectBuilder.ts +39 -0
  30. package/src/queryBuilder/SelectQueryBuilder.ts +93 -0
  31. package/src/queryBuilder/UpdateBuilder.ts +44 -0
  32. package/src/queryBuilder/addWhereClause.ts +35 -0
  33. package/src/queryBuilder/index.ts +7 -0
  34. package/src/queryBuilder/operators.ts +35 -0
  35. package/src/queryBuilder/queryBuilders.types.ts +105 -0
  36. package/src/queryGenerator/Clause.ts +79 -0
  37. package/src/queryGenerator/generateDelete.ts +18 -0
  38. package/src/queryGenerator/generateInsert.ts +29 -0
  39. package/src/queryGenerator/generateSelect.ts +89 -0
  40. package/src/queryGenerator/generateUpdate.ts +29 -0
  41. package/src/queryGenerator/index.ts +4 -0
  42. package/src/reflection/Reflector.ts +47 -0
  43. package/src/reflection/index.ts +2 -0
  44. package/src/reflection/reflection.types.ts +12 -0
  45. package/src/schemaBuilder/Mapping.ts +44 -0
  46. package/src/schemaBuilder/columnBuilders.ts +67 -0
  47. package/src/schemaBuilder/createFixture.ts +112 -0
  48. package/src/schemaBuilder/createIndex.ts +33 -0
  49. package/src/schemaBuilder/createSchema.ts +23 -0
  50. package/src/schemaBuilder/createTable.ts +80 -0
  51. package/src/schemaBuilder/createView.ts +21 -0
  52. package/src/schemaBuilder/index.ts +9 -0
  53. package/src/schemaBuilder/metadata.ts +73 -0
  54. package/src/schemaBuilder/schemaBuilder.types.ts +139 -0
  55. package/src/schemaGenerator/generateCreateIndex.ts +18 -0
  56. package/src/schemaGenerator/generateCreateTable.ts +68 -0
  57. package/src/schemaGenerator/generateCreateView.ts +13 -0
  58. package/src/schemaGenerator/index.ts +3 -0
@@ -0,0 +1,29 @@
1
+ import { join, newline, print } from "@sigitex/print"
2
+ import { Format } from "../framework"
3
+ import type { InsertCommand } from "../queryBuilder"
4
+ import { Clause } from "./Clause"
5
+
6
+ export function generateInsert({
7
+ table,
8
+ columns,
9
+ rows,
10
+ returning,
11
+ }: InsertCommand) {
12
+ return print([
13
+ "insert into ",
14
+ Format.name(table),
15
+ " (",
16
+ join(", ", columns, Format.name),
17
+ ")",
18
+ newline,
19
+ "values ",
20
+ rows.map((row, i) => [
21
+ i > 0 && ", ",
22
+ "(",
23
+ columns.map((col, c) => [c > 0 && ", ", Format.value(row[col])]),
24
+ ")",
25
+ ]),
26
+ newline,
27
+ returning && Clause.returning(returning),
28
+ ])
29
+ }
@@ -0,0 +1,89 @@
1
+ import { indent, join, newline, type Node, print } from "@sigitex/print"
2
+ import { Format } from "../framework"
3
+ import type { JoinClause, OrderBySort, SelectQuery } from "../queryBuilder"
4
+ import { Clause } from "./Clause"
5
+
6
+ export function generateSelect(query: SelectQuery) {
7
+ return print([generateSelectNode(query)])
8
+ }
9
+
10
+ export function generateSelectNode({
11
+ selected,
12
+ table,
13
+ conditions,
14
+ limit,
15
+ offset,
16
+ orderBy,
17
+ joins,
18
+ }: SelectQuery): Node {
19
+ const hasJoins = !!joins?.length
20
+ const aliasMap = hasJoins ? buildAliasMap(table, joins!) : undefined
21
+ return [
22
+ "select ",
23
+ selected &&
24
+ join(", ", selected, (col: string) =>
25
+ hasJoins ? qualifyColumn(table, col) : Format.name(col),
26
+ ),
27
+ !selected &&
28
+ (hasJoins ? allColumnsQualified(table, joins!, aliasMap!) : "*"),
29
+ newline,
30
+ "from ",
31
+ Format.name(table),
32
+ newline,
33
+ hasJoins && Clause.joins(joins!, aliasMap!),
34
+ conditions?.length &&
35
+ Clause.where(conditions, hasJoins ? table : undefined),
36
+ limit && ["limit ", Format.number(limit), newline],
37
+ offset && ["offset ", Format.number(offset), newline],
38
+ orderBy && orderByClause(orderBy),
39
+ ]
40
+ }
41
+
42
+ function buildAliasMap(
43
+ baseTable: string,
44
+ joins: JoinClause[],
45
+ ): Map<JoinClause, string> {
46
+ const map = new Map<JoinClause, string>()
47
+ const used = new Set([baseTable])
48
+
49
+ for (const clause of joins) {
50
+ const sourceName =
51
+ clause.target.kind === "table" ? clause.target.name : clause.target.table
52
+ let alias = sourceName
53
+ let i = 1
54
+ while (used.has(alias)) {
55
+ alias = `${sourceName}_${i++}`
56
+ }
57
+ used.add(alias)
58
+ map.set(clause, alias)
59
+ }
60
+ return map
61
+ }
62
+
63
+ function qualifyColumn(baseTable: string, column: string): string {
64
+ return `${Format.name(baseTable)}.${Format.name(column)}`
65
+ }
66
+
67
+ function allColumnsQualified(
68
+ table: string,
69
+ joins: JoinClause[],
70
+ aliasMap: Map<JoinClause, string>,
71
+ ): Node {
72
+ const names = [table, ...joins.map((j) => aliasMap.get(j)!)]
73
+ return names.map((t, i) => [i > 0 && ", ", Format.name(t), ".*"])
74
+ }
75
+
76
+ function orderByClause(orderBy: OrderBySort[]): Node {
77
+ return [
78
+ "order by ",
79
+ indent(
80
+ orderBy.map(({ column, direction }, index) => [
81
+ index > 0 && ", ",
82
+ Format.name(column),
83
+ " ",
84
+ direction,
85
+ newline,
86
+ ]),
87
+ ),
88
+ ]
89
+ }
@@ -0,0 +1,29 @@
1
+ import { indent, newline, print } from "@sigitex/print"
2
+ import { Format } from "../framework"
3
+ import type { UpdateCommand } from "../queryBuilder"
4
+ import { Clause } from "./Clause"
5
+
6
+ export function generateUpdate({
7
+ table,
8
+ assignments,
9
+ conditions,
10
+ returning,
11
+ }: UpdateCommand) {
12
+ const columns = Object.keys(assignments)
13
+ return print([
14
+ "update ",
15
+ Format.name(table),
16
+ newline,
17
+ "set ",
18
+ indent(
19
+ columns.map((col, i) => [
20
+ i > 0 && [",", newline],
21
+ Format.name(col),
22
+ " = ",
23
+ Format.value(assignments[col]),
24
+ ]),
25
+ ),
26
+ conditions?.length && Clause.where(conditions),
27
+ returning && Clause.returning(returning),
28
+ ])
29
+ }
@@ -0,0 +1,4 @@
1
+ export * from "./generateSelect"
2
+ export * from "./generateInsert"
3
+ export * from "./generateUpdate"
4
+ export * from "./generateDelete"
@@ -0,0 +1,47 @@
1
+ import type { Connection } from "../api"
2
+ import type { TableListItem } from "./reflection.types"
3
+
4
+ export class Reflector {
5
+ private readonly connection: Connection
6
+ private tableListItems: TableListItem[] | undefined = undefined
7
+
8
+ constructor(connection: Connection) {
9
+ this.connection = connection
10
+ }
11
+
12
+ async hasTable(tableName: string) {
13
+ return (await this.getTableList()).some(
14
+ ({ name, type }) => type === "table" && name === tableName,
15
+ )
16
+ }
17
+
18
+ async isMissingTable(tableName: string) {
19
+ return !(await this.hasTable(tableName))
20
+ }
21
+
22
+ async hasView(viewName: string) {
23
+ return (await this.getTableList()).some(
24
+ ({ name, type }) => type === "view" && name === viewName,
25
+ )
26
+ }
27
+
28
+ async hasIndex(indexName: string) {
29
+ const results = await this.connection.query<{ name: string }>(
30
+ `select name from sqlite_master where type = 'index' and name = '${indexName}'`,
31
+ )
32
+ return results.length > 0
33
+ }
34
+
35
+ invalidate() {
36
+ this.tableListItems = undefined
37
+ }
38
+
39
+ private async getTableList() {
40
+ if (this.tableListItems === undefined) {
41
+ const results =
42
+ await this.connection.query<TableListItem>("pragma table_list")
43
+ this.tableListItems = results.filter(({ schema }) => schema === "main")
44
+ }
45
+ return this.tableListItems
46
+ }
47
+ }
@@ -0,0 +1,2 @@
1
+ export * from "./reflection.types"
2
+ export * from "./Reflector"
@@ -0,0 +1,12 @@
1
+ export type TableListType = "table" | "view" | "shadow" | "virtual"
2
+
3
+ export type TableListItem = {
4
+ readonly schema: string
5
+ readonly name: string
6
+ readonly type: TableListType
7
+ /** Number of columns **/
8
+ readonly ncol: number
9
+ /** WITHOUT ROWID */
10
+ readonly wr: number
11
+ strict: number
12
+ }
@@ -0,0 +1,44 @@
1
+ export type Mapping<From, To> = {
2
+ from(value: From): To
3
+ to(value: To): From
4
+ }
5
+
6
+ export namespace Mapping {
7
+ export const boolean: Mapping<number, boolean> = {
8
+ from(n) {
9
+ return n !== 0
10
+ },
11
+ to(b) {
12
+ return b ? 1 : 0
13
+ },
14
+ }
15
+
16
+ export const timestamp: Mapping<number, Date> = {
17
+ from(n) {
18
+ return new Date(n)
19
+ },
20
+ to(d) {
21
+ return d.getTime()
22
+ },
23
+ }
24
+
25
+ export const date: Mapping<string, Date> = {
26
+ from(s) {
27
+ return new Date(s)
28
+ },
29
+ to(d) {
30
+ return d.toISOString()
31
+ },
32
+ }
33
+
34
+ export function json<T>(): Mapping<string, T> {
35
+ return {
36
+ from(s) {
37
+ return JSON.parse(s) as T
38
+ },
39
+ to(o) {
40
+ return JSON.stringify(o)
41
+ },
42
+ }
43
+ }
44
+ }
@@ -0,0 +1,67 @@
1
+ // oxlint-disable typescript/no-explicit-any
2
+ import type { CheckExpression, ColumnData, ColumnRef, MappingData } from "./metadata"
3
+ import { Mapping } from "./Mapping"
4
+ import type {
5
+ BuildColumn,
6
+ BuildColumnInner,
7
+ BuildColumnMap,
8
+ BuildPrimaryKey,
9
+ } from "./schemaBuilder.types"
10
+
11
+ export const text: BuildColumn<string, never> = composeColumn({
12
+ datatype: "text",
13
+ })
14
+ export const integer: BuildColumn<number, never> = composeColumn({
15
+ datatype: "integer",
16
+ })
17
+ export const real: BuildColumn<number, never> = composeColumn({
18
+ datatype: "real",
19
+ })
20
+ export const blob: BuildColumn<ArrayBuffer, never> = composeColumn({
21
+ datatype: "blob",
22
+ })
23
+
24
+ function composeColumn(
25
+ $meta: Partial<ColumnData>,
26
+ ): BuildColumnInner & BuildPrimaryKey<any, never> {
27
+ return {
28
+ $meta,
29
+ get notNull() {
30
+ return composeColumn({ ...$meta, notNull: true })
31
+ },
32
+ get primaryKey() {
33
+ return composeColumn({ ...$meta, primaryKey: { autoincrement: false } })
34
+ },
35
+ get autoincrement() {
36
+ return composeColumn({ ...$meta, primaryKey: { autoincrement: true } })
37
+ },
38
+ default(sql) {
39
+ return composeColumn({ ...$meta, default: sql })
40
+ },
41
+ check(expression: CheckExpression) {
42
+ return composeColumn({ ...$meta, check: expression })
43
+ },
44
+ get unique() {
45
+ return composeColumn({ ...$meta, unique: true })
46
+ },
47
+ get foreignKey() {
48
+ return {
49
+ references(ref: ColumnRef) {
50
+ return composeColumn({
51
+ ...$meta,
52
+ foreignKey: ref,
53
+ })
54
+ },
55
+ }
56
+ },
57
+ get map(): BuildColumnMap<any, never> {
58
+ const custom = (mapping?: MappingData) =>
59
+ composeColumn(mapping ? { ...$meta, mapping } : $meta)
60
+ custom.boolean = composeColumn({ ...$meta, mapping: Mapping.boolean })
61
+ custom.timestamp = composeColumn({ ...$meta, mapping: Mapping.timestamp })
62
+ custom.date = composeColumn({ ...$meta, mapping: Mapping.date })
63
+ custom.json = () => composeColumn({ ...$meta, mapping: Mapping.json() })
64
+ return custom as BuildColumnMap<any, never>
65
+ },
66
+ }
67
+ }
@@ -0,0 +1,112 @@
1
+ // oxlint-disable typescript/no-explicit-any
2
+ import type { AnyBuildTable, InferTable, RefBy } from "./schemaBuilder.types"
3
+
4
+ export type Fixtures = {
5
+ [key: string]: Fixture<any>
6
+ }
7
+
8
+ export type Seeds = Fixtures
9
+
10
+ export type FixtureRow<Table> = {
11
+ [K in keyof InferTable<Table>]: InferTable<Table>[K] | RefBy
12
+ }
13
+
14
+ export type Fixture<Table> = {
15
+ table: Table
16
+ rows: FixtureRow<Table>[]
17
+ }
18
+
19
+ export namespace Fixture {
20
+ export function isRefBy(value: unknown): value is RefBy {
21
+ return (
22
+ value != null &&
23
+ typeof value === "object" &&
24
+ (value as any)._tag === "RefBy"
25
+ )
26
+ }
27
+ }
28
+
29
+ // TODO: just call it Row<Table>, avoid this alias
30
+ type Row<Table> = InferTable<Table>
31
+
32
+ type AllowRefBy<T> = T | RefBy
33
+
34
+ export type FixtureTemplate<Table> = {
35
+ [K in keyof Row<Table>]?: AllowRefBy<Row<Table>[K]> | (() => Row<Table>[K])
36
+ }
37
+
38
+ type TemplateKeys<Template> = keyof {
39
+ [K in keyof Template as Template[K] extends undefined ? never : K]: true
40
+ }
41
+
42
+ type NullableKeys<T> = {
43
+ [K in keyof T]: null extends T[K] ? K : never
44
+ }[keyof T]
45
+
46
+ type RequiredRows<Table, Template> = {
47
+ [K in keyof Omit<
48
+ Row<Table>,
49
+ TemplateKeys<Template> | NullableKeys<Row<Table>>
50
+ >]: AllowRefBy<Row<Table>[K]>
51
+ }
52
+
53
+ type OptionalRows<Table, Template> = Partial<{
54
+ [K in (TemplateKeys<Template> | NullableKeys<Row<Table>>) &
55
+ keyof Row<Table>]: AllowRefBy<Row<Table>[K]>
56
+ }>
57
+
58
+ export type FixtureRows<Table, Template> = RequiredRows<Table, Template> &
59
+ OptionalRows<Table, Template>
60
+
61
+ export function createFixture<
62
+ Table extends AnyBuildTable,
63
+ const Template extends FixtureTemplate<Table>,
64
+ >(
65
+ table: Table,
66
+ template: Template,
67
+ rows: FixtureRows<Table, Template>[],
68
+ ): Fixture<Table>
69
+
70
+ export function createFixture<Table extends AnyBuildTable>(
71
+ table: Table,
72
+ rows: InferTable<Table>[],
73
+ ): Fixture<Table>
74
+
75
+ export function createFixture(
76
+ table: AnyBuildTable,
77
+ templateOrRows: Record<string, unknown> | Record<string, unknown>[],
78
+ maybeRows?: Record<string, unknown>[],
79
+ ): Fixture<AnyBuildTable> {
80
+ if (Array.isArray(templateOrRows)) {
81
+ return { table, rows: templateOrRows } as any
82
+ }
83
+
84
+ const template = templateOrRows
85
+ const rows = maybeRows!
86
+
87
+ const nullableKeys = table.$meta.columns
88
+ .filter((col) => !col.notNull && !col.primaryKey)
89
+ .map((col) => col.name)
90
+
91
+ return {
92
+ table,
93
+ rows: rows.map((row) => {
94
+ const result: Record<string, unknown> = { ...row }
95
+ for (const key of nullableKeys) {
96
+ if (!(key in result) && !(key in template)) {
97
+ result[key] = null
98
+ }
99
+ }
100
+ for (const key in template) {
101
+ if (key in row) {
102
+ continue
103
+ }
104
+ const value = template[key]
105
+ result[key] = typeof value === "function" ? value() : value
106
+ }
107
+ return result
108
+ }),
109
+ } as any
110
+ }
111
+
112
+ export const createSeed = createFixture
@@ -0,0 +1,33 @@
1
+ import type { ColumnRef, IndexData } from "./metadata"
2
+ import type { BuildIndex } from "./schemaBuilder.types"
3
+
4
+ export function createIndex(name: string): IndexOn {
5
+ return {
6
+ on(...columns: ColumnRef[]) {
7
+ return finalize(name, columns, false)
8
+ },
9
+ }
10
+ }
11
+
12
+ export function createUniqueIndex(name: string): IndexOn {
13
+ return {
14
+ on(...columns: ColumnRef[]) {
15
+ return finalize(name, columns, true)
16
+ },
17
+ }
18
+ }
19
+
20
+ type IndexOn = {
21
+ on(...columns: ColumnRef[]): BuildIndex
22
+ }
23
+
24
+ function finalize(name: string, columns: ColumnRef[], unique: boolean): BuildIndex {
25
+ const $meta: IndexData = {
26
+ kind: "index",
27
+ name,
28
+ table: columns[0].table,
29
+ columns: columns.map(c => c.column),
30
+ unique,
31
+ }
32
+ return { $kind: "index", $meta }
33
+ }
@@ -0,0 +1,23 @@
1
+ import type { Schema, SchemaMembers } from "./schemaBuilder.types"
2
+
3
+ export function createSchema<M extends SchemaMembers>(
4
+ members: M,
5
+ ): Schema<M> {
6
+ const tables: Record<string, unknown> = {}
7
+ const views: Record<string, unknown> = {}
8
+ const indexes: Record<string, unknown> = {}
9
+ for (const [key, member] of Object.entries(members)) {
10
+ switch (member.$kind) {
11
+ case "table":
12
+ tables[key] = member
13
+ break
14
+ case "view":
15
+ views[key] = member
16
+ break
17
+ case "index":
18
+ indexes[key] = member
19
+ break
20
+ }
21
+ }
22
+ return { tables, views, indexes } as Schema<M>
23
+ }
@@ -0,0 +1,80 @@
1
+ import type { ColumnData, ColumnRef, TableData } from "./metadata"
2
+ import type {
3
+ BuildColumns,
4
+ BuildColumnInner,
5
+ BuildTable,
6
+ } from "./schemaBuilder.types"
7
+ import { SelectQueryBuilder } from "../queryBuilder/SelectQueryBuilder"
8
+
9
+ export function createTable<Columns extends BuildColumns>(
10
+ name: string,
11
+ defineColumns: Columns,
12
+ ): BuildTable<Columns> {
13
+ const columns = Object.entries(defineColumns).map<ColumnData>(
14
+ ([name, define]) => {
15
+ const meta = (define as BuildColumnInner).$meta
16
+ return {
17
+ name,
18
+ datatype: meta.datatype!,
19
+ default: meta.default,
20
+ foreignKey: meta.foreignKey,
21
+ notNull: !!meta.notNull,
22
+ primaryKey: meta.primaryKey,
23
+ unique: !!meta.unique,
24
+ mapping: meta.mapping,
25
+ check: meta.check,
26
+ }
27
+ },
28
+ )
29
+ const $meta: TableData = {
30
+ name,
31
+ columns,
32
+ constraints: [],
33
+ }
34
+ const by = new Proxy({}, {
35
+ get(_, col: string) {
36
+ return (value: unknown) => ({
37
+ _tag: "RefBy" as const,
38
+ table: defineTable,
39
+ column: col,
40
+ value,
41
+ })
42
+ },
43
+ })
44
+ function select(...columns: ("*" | string)[]) {
45
+ if (columns[0] === "*" || columns.length === 0) {
46
+ return new SelectQueryBuilder($meta, "*")
47
+ }
48
+ return new SelectQueryBuilder($meta, columns)
49
+ }
50
+ const defineTable = { $kind: "table" as const, $meta, by, primaryKey, unique, check, select } as unknown as BuildTable<Columns>
51
+ for (const col of Object.keys(defineColumns)) {
52
+ // oxlint-disable-next-line typescript/no-explicit-any
53
+ ;(defineTable as any)[col] = { table: name, column: col } satisfies ColumnRef
54
+ }
55
+ return defineTable
56
+
57
+ function primaryKey(...columns: (keyof Columns)[]) {
58
+ $meta.constraints.push({
59
+ type: "primaryKey",
60
+ columns: columns as string[],
61
+ })
62
+ return defineTable
63
+ }
64
+
65
+ function unique(...columns: (keyof Columns)[]) {
66
+ $meta.constraints.push({
67
+ type: "unique",
68
+ columns: columns as string[],
69
+ })
70
+ return defineTable
71
+ }
72
+
73
+ function check(expression: string | ((columns: Record<string, string>, table: TableData) => string)) {
74
+ $meta.constraints.push({
75
+ type: "check",
76
+ expression,
77
+ })
78
+ return defineTable
79
+ }
80
+ }
@@ -0,0 +1,21 @@
1
+ // oxlint-disable typescript/no-explicit-any
2
+ import { print } from "@sigitex/print"
3
+ import { generateSelectNode } from "../queryGenerator/generateSelect"
4
+ import type { SelectQueryBuilder } from "../queryBuilder/SelectQueryBuilder"
5
+ import type { TableData, ViewData } from "./metadata"
6
+ import type { BuildView, SchemaSelect } from "./schemaBuilder.types"
7
+
8
+ export function createView<SelectColumns>(
9
+ name: string,
10
+ queryBuilder: SchemaSelect<SelectColumns, any>,
11
+ ): BuildView<SelectColumns> {
12
+ const builder = queryBuilder as unknown as SelectQueryBuilder
13
+ const sql = print([generateSelectNode(builder.query)])
14
+ const $meta: ViewData = { kind: "view", name, sql }
15
+ const allColumns = [
16
+ ...builder.table.columns,
17
+ ...(builder.query.joins?.flatMap(j => j.target.tableData.columns) ?? []),
18
+ ]
19
+ const $tableData: TableData = { name, columns: allColumns, constraints: [] }
20
+ return { $kind: "view", $meta, $tableData }
21
+ }
@@ -0,0 +1,9 @@
1
+ export * from "./Mapping"
2
+ export * from "./metadata"
3
+ export * from "./schemaBuilder.types"
4
+ export * from "./createSchema"
5
+ export * from "./createTable"
6
+ export * from "./createIndex"
7
+ export * from "./createView"
8
+ export * from "./columnBuilders"
9
+ export * from "./createFixture"
@@ -0,0 +1,73 @@
1
+ // oxlint-disable typescript/no-explicit-any
2
+ export type Text = "text"
3
+ export type Integer = "integer"
4
+ export type Real = "real"
5
+ export type Blob = "blob"
6
+
7
+ export type Datatype = Text | Integer | Real | Blob
8
+
9
+ export type JSType = string | number | ArrayBuffer
10
+
11
+ export type MappingData = { from(value: any): any; to(value: any): any }
12
+
13
+ export type TableData = {
14
+ readonly name: string
15
+ readonly columns: ColumnData[]
16
+ readonly constraints: TableConstraintData[]
17
+ }
18
+
19
+ export type CheckExpression = string | ((name: string, column: ColumnData) => string)
20
+
21
+ export type ColumnData = {
22
+ readonly name: string
23
+ readonly datatype: Datatype
24
+ readonly notNull: boolean
25
+ readonly primaryKey: PrimaryKeyData | undefined
26
+ readonly default: string | undefined
27
+ readonly unique: boolean
28
+ readonly foreignKey: ForeignKeyData | undefined
29
+ readonly mapping: MappingData | undefined
30
+ readonly check: CheckExpression | undefined
31
+ }
32
+
33
+ export type ColumnRef = {
34
+ readonly table: string
35
+ readonly column: string
36
+ }
37
+
38
+ export type ForeignKeyData = ColumnRef
39
+
40
+ export type TableConstraintData = TablePrimaryKeyData | TableUniqueData | TableCheckData
41
+
42
+ export type TablePrimaryKeyData = {
43
+ readonly type: "primaryKey"
44
+ readonly columns: string[]
45
+ }
46
+
47
+ export type TableUniqueData = {
48
+ readonly type: "unique"
49
+ readonly columns: string[]
50
+ }
51
+
52
+ export type TableCheckData = {
53
+ readonly type: "check"
54
+ readonly expression: string | ((columns: Record<string, string>, table: TableData) => string)
55
+ }
56
+
57
+ export type PrimaryKeyData = {
58
+ readonly autoincrement: boolean
59
+ }
60
+
61
+ export type IndexData = {
62
+ readonly kind: "index"
63
+ readonly name: string
64
+ readonly table: string
65
+ readonly columns: string[]
66
+ readonly unique: boolean
67
+ }
68
+
69
+ export type ViewData = {
70
+ readonly kind: "view"
71
+ readonly name: string
72
+ readonly sql: string
73
+ }