@casekit/orm-schema 0.0.1-release-candidate
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.
- package/build/Config.d.ts +17 -0
- package/build/Config.js +1 -0
- package/build/Logger.d.ts +6 -0
- package/build/Logger.js +1 -0
- package/build/definition/FieldDefinition.d.ts +74 -0
- package/build/definition/FieldDefinition.js +1 -0
- package/build/definition/ForeignKeyDefinition.d.ts +10 -0
- package/build/definition/ForeignKeyDefinition.js +1 -0
- package/build/definition/ModelDefinition.d.ts +43 -0
- package/build/definition/ModelDefinition.js +1 -0
- package/build/definition/ModelDefinitions.d.ts +2 -0
- package/build/definition/ModelDefinitions.js +1 -0
- package/build/definition/OperatorDefinitions.d.ts +4 -0
- package/build/definition/OperatorDefinitions.js +1 -0
- package/build/definition/PostgresDataTypes.d.ts +78 -0
- package/build/definition/PostgresDataTypes.js +1 -0
- package/build/definition/RelationDefinition.d.ts +23 -0
- package/build/definition/RelationDefinition.js +1 -0
- package/build/definition/RelationDefinitions.d.ts +2 -0
- package/build/definition/RelationDefinitions.js +1 -0
- package/build/definition/UniqueConstraintDefinition.d.ts +7 -0
- package/build/definition/UniqueConstraintDefinition.js +1 -0
- package/build/definition/WhereOperator.d.ts +5 -0
- package/build/definition/WhereOperator.js +1 -0
- package/build/helper/DefaultFieldType.d.ts +7 -0
- package/build/helper/DefaultFieldType.js +1 -0
- package/build/helper/DefaultFieldType.test-d.d.ts +1 -0
- package/build/helper/DefaultFieldType.test-d.js +57 -0
- package/build/helper/FieldName.d.ts +2 -0
- package/build/helper/FieldName.js +1 -0
- package/build/helper/FieldName.test-d.d.ts +1 -0
- package/build/helper/FieldName.test-d.js +16 -0
- package/build/helper/FieldType.d.ts +5 -0
- package/build/helper/FieldType.js +1 -0
- package/build/helper/FieldType.test-d.d.ts +1 -0
- package/build/helper/FieldType.test-d.js +59 -0
- package/build/helper/FieldWithDefault.d.ts +4 -0
- package/build/helper/FieldWithDefault.js +1 -0
- package/build/helper/FieldWithDefault.test-d.d.ts +1 -0
- package/build/helper/FieldWithDefault.test-d.js +35 -0
- package/build/helper/ModelName.d.ts +2 -0
- package/build/helper/ModelName.js +1 -0
- package/build/helper/ModelName.test-d.d.ts +1 -0
- package/build/helper/ModelName.test-d.js +14 -0
- package/build/helper/ModelType.d.ts +6 -0
- package/build/helper/ModelType.js +1 -0
- package/build/helper/ModelType.test-d.d.ts +1 -0
- package/build/helper/ModelType.test-d.js +37 -0
- package/build/helper/NullableField.d.ts +4 -0
- package/build/helper/NullableField.js +1 -0
- package/build/helper/NullableField.test-d.d.ts +1 -0
- package/build/helper/NullableField.test-d.js +34 -0
- package/build/helper/OptionalField.d.ts +4 -0
- package/build/helper/OptionalField.js +1 -0
- package/build/helper/OptionalField.test-d.d.ts +1 -0
- package/build/helper/OptionalField.test-d.js +39 -0
- package/build/helper/ProvidedField.d.ts +4 -0
- package/build/helper/ProvidedField.js +1 -0
- package/build/helper/ProvidedField.test-d.d.ts +1 -0
- package/build/helper/ProvidedField.test-d.js +34 -0
- package/build/helper/RelationModel.d.ts +4 -0
- package/build/helper/RelationModel.js +1 -0
- package/build/helper/RelationModel.test-d.d.ts +1 -0
- package/build/helper/RelationModel.test-d.js +60 -0
- package/build/helper/RelationName.d.ts +2 -0
- package/build/helper/RelationName.js +1 -0
- package/build/helper/RelationName.test-d.d.ts +1 -0
- package/build/helper/RelationName.test-d.js +44 -0
- package/build/helper/RequiredField.d.ts +7 -0
- package/build/helper/RequiredField.js +1 -0
- package/build/helper/RequiredField.test-d.d.ts +1 -0
- package/build/helper/RequiredField.test-d.js +39 -0
- package/build/helper/SerialField.d.ts +4 -0
- package/build/helper/SerialField.js +1 -0
- package/build/helper/SerialField.test-d.d.ts +1 -0
- package/build/helper/SerialField.test-d.js +46 -0
- package/build/index.d.ts +25 -0
- package/build/index.js +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import pg from "pg";
|
|
2
|
+
import { Logger } from "./Logger.js";
|
|
3
|
+
import { ModelDefinitions } from "./definition/ModelDefinitions.js";
|
|
4
|
+
import { OperatorDefinitions } from "./definition/OperatorDefinitions.js";
|
|
5
|
+
export interface Config {
|
|
6
|
+
readonly schema?: string;
|
|
7
|
+
readonly models: ModelDefinitions;
|
|
8
|
+
readonly operators?: OperatorDefinitions;
|
|
9
|
+
readonly extensions?: readonly string[];
|
|
10
|
+
readonly connection?: pg.ConnectionConfig | pg.PoolConfig | pg.PoolOptions | null;
|
|
11
|
+
readonly pool?: boolean;
|
|
12
|
+
readonly logger?: Logger;
|
|
13
|
+
readonly naming?: {
|
|
14
|
+
readonly column?: (name: string) => string;
|
|
15
|
+
readonly table?: (name: string) => string;
|
|
16
|
+
};
|
|
17
|
+
}
|
package/build/Config.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/build/Logger.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { SQLStatement } from "@casekit/sql";
|
|
3
|
+
import { PostgresDataTypes } from "./PostgresDataTypes.js";
|
|
4
|
+
export interface FieldDefinition {
|
|
5
|
+
/**
|
|
6
|
+
* The name of the column in the database. If not specified,
|
|
7
|
+
* it will be inferred based on the model's field name,
|
|
8
|
+
* with any column naming function (e.g. `snakeCase`) specified
|
|
9
|
+
* in the config applied.
|
|
10
|
+
*/
|
|
11
|
+
column?: string;
|
|
12
|
+
/**
|
|
13
|
+
* The postgresql datatype of the column.
|
|
14
|
+
*/
|
|
15
|
+
type: `${PostgresDataTypes[keyof PostgresDataTypes]}${string}` | `${Uppercase<PostgresDataTypes[keyof PostgresDataTypes]>}${string}`;
|
|
16
|
+
/**
|
|
17
|
+
* A Zod schema used to infer the type of the column and to
|
|
18
|
+
* validate/transform data coming from the database.
|
|
19
|
+
* If not specified, an attempt will be made to infer a basic schema
|
|
20
|
+
* based on the postgresql data type of the column. Specifying it
|
|
21
|
+
* allows to you configure more sophisticated parsing, validation,
|
|
22
|
+
* and transformations.
|
|
23
|
+
*/
|
|
24
|
+
zodSchema?: z.ZodType;
|
|
25
|
+
/**
|
|
26
|
+
* Are null values allowed in this column?
|
|
27
|
+
*/
|
|
28
|
+
nullable?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* The default value for this column, if it has one. This can be either a value such
|
|
31
|
+
* as a number or string, or if you want to specify a SQL function for the default,
|
|
32
|
+
* you can use the `sql` tagged template literal. Examples include:
|
|
33
|
+
*
|
|
34
|
+
* default: 3,
|
|
35
|
+
*
|
|
36
|
+
* or
|
|
37
|
+
*
|
|
38
|
+
* default: "foo",
|
|
39
|
+
*
|
|
40
|
+
* or
|
|
41
|
+
*
|
|
42
|
+
* default: sql`uuid_generate_v4()`,
|
|
43
|
+
*/
|
|
44
|
+
default?: unknown;
|
|
45
|
+
/**
|
|
46
|
+
* Is this column unique? If so, you can specify a where clause to
|
|
47
|
+
* specify a partial unique index, and whether nulls should be considered
|
|
48
|
+
* distinct.
|
|
49
|
+
*/
|
|
50
|
+
unique?: boolean | {
|
|
51
|
+
where?: SQLStatement | null;
|
|
52
|
+
nullsNotDistinct?: boolean;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Is this column a single-column primary key?
|
|
56
|
+
*/
|
|
57
|
+
primaryKey?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Is this column a foreign key? If so, you can specify the table and column it references,
|
|
60
|
+
* and what should happen on update or delete.
|
|
61
|
+
*/
|
|
62
|
+
references?: {
|
|
63
|
+
schema?: string;
|
|
64
|
+
model: string;
|
|
65
|
+
field: string;
|
|
66
|
+
onUpdate?: "RESTRICT" | "CASCADE" | "SET NULL" | "SET DEFAULT" | null;
|
|
67
|
+
onDelete?: "RESTRICT" | "CASCADE" | "SET NULL" | "SET DEFAULT" | null;
|
|
68
|
+
} | null;
|
|
69
|
+
/**
|
|
70
|
+
* Is this column provided by middleware? If so, it will not be included in
|
|
71
|
+
* the set of required columns for inserts and updates.
|
|
72
|
+
*/
|
|
73
|
+
provided?: boolean;
|
|
74
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface ForeignKeyDefinition {
|
|
2
|
+
name?: string;
|
|
3
|
+
fields: Array<string>;
|
|
4
|
+
references: {
|
|
5
|
+
model: string;
|
|
6
|
+
fields: string[];
|
|
7
|
+
};
|
|
8
|
+
onUpdate?: "RESTRICT" | "CASCADE" | "SET NULL" | "SET DEFAULT" | null;
|
|
9
|
+
onDelete?: "RESTRICT" | "CASCADE" | "SET NULL" | "SET DEFAULT" | null;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { FieldDefinition } from "./FieldDefinition.js";
|
|
2
|
+
import { ForeignKeyDefinition } from "./ForeignKeyDefinition.js";
|
|
3
|
+
import { RelationDefinitions } from "./RelationDefinitions.js";
|
|
4
|
+
import { UniqueConstraintDefinition } from "./UniqueConstraintDefinition.js";
|
|
5
|
+
/**
|
|
6
|
+
* Configuration object for a database model.
|
|
7
|
+
*/
|
|
8
|
+
export interface ModelDefinition {
|
|
9
|
+
/**
|
|
10
|
+
* The name of the model's table. If not specified, the table name will be
|
|
11
|
+
* derived from the model name, with any transform function specified in
|
|
12
|
+
* config applied.
|
|
13
|
+
*/
|
|
14
|
+
table?: string;
|
|
15
|
+
/**
|
|
16
|
+
* The schema in which the model sits. If not specified, will use the
|
|
17
|
+
* schema specified in the global config; if no schema is specified in
|
|
18
|
+
* the global config, will be set to `public`.
|
|
19
|
+
*/
|
|
20
|
+
schema?: string;
|
|
21
|
+
/**
|
|
22
|
+
* The model's fields - a map of field name to field
|
|
23
|
+
* definitions. The keys of this map will be used in generated functions
|
|
24
|
+
* and object fields, so must be valid Javascript identifiers.
|
|
25
|
+
*/
|
|
26
|
+
fields: Record<string, FieldDefinition>;
|
|
27
|
+
/**
|
|
28
|
+
* If the table's primary key contains multiple columns, specify them here.
|
|
29
|
+
* If the primary key is on a single column, you can specify it here or in the column definition.
|
|
30
|
+
*/
|
|
31
|
+
primaryKey?: string[] | null;
|
|
32
|
+
/**
|
|
33
|
+
* If the table has unique constraints that span multiple columns, you must specify them here.
|
|
34
|
+
* If the unique constraint is on a single column, you can specify it here or in the column definition.
|
|
35
|
+
*/
|
|
36
|
+
uniqueConstraints?: UniqueConstraintDefinition[];
|
|
37
|
+
/**
|
|
38
|
+
* If the table has foreign keys, you must specify them here. If the foreign key is on a single column,
|
|
39
|
+
* you can specify it here or in the column definition.
|
|
40
|
+
*/
|
|
41
|
+
foreignKeys?: ForeignKeyDefinition[];
|
|
42
|
+
relations?: RelationDefinitions;
|
|
43
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export interface PostgresDataTypes {
|
|
2
|
+
bigint: "bigint";
|
|
3
|
+
bigserial: "bigserial";
|
|
4
|
+
bit: `bit`;
|
|
5
|
+
bit_n: `bit (${number})`;
|
|
6
|
+
bit_varying: `bit varying`;
|
|
7
|
+
bit_varying_n: `bit varying (${number})`;
|
|
8
|
+
boolean: "boolean";
|
|
9
|
+
box: "box";
|
|
10
|
+
bytea: "bytea";
|
|
11
|
+
char: `char`;
|
|
12
|
+
character: `character`;
|
|
13
|
+
character_n: `character (${number})`;
|
|
14
|
+
character_varying: `character varying`;
|
|
15
|
+
character_varying_n: `character varying (${number})`;
|
|
16
|
+
cidr: "cidr";
|
|
17
|
+
date: "date";
|
|
18
|
+
daterange: "daterange";
|
|
19
|
+
double_precision: "double precision";
|
|
20
|
+
inet: "inet";
|
|
21
|
+
int2vector: "int2vector";
|
|
22
|
+
int4range: "int4range";
|
|
23
|
+
int8range: "int8range";
|
|
24
|
+
integer: "integer";
|
|
25
|
+
json: "json";
|
|
26
|
+
jsonb: "jsonb";
|
|
27
|
+
line: "line";
|
|
28
|
+
lseg: "lseg";
|
|
29
|
+
macaddr: "macaddr";
|
|
30
|
+
macaddr8: "macaddr8";
|
|
31
|
+
money: "money";
|
|
32
|
+
numeric: "numeric";
|
|
33
|
+
numeric_p_s: `numeric (${number}, ${number})`;
|
|
34
|
+
numrange: "numrange";
|
|
35
|
+
oid: "oid";
|
|
36
|
+
path: "path";
|
|
37
|
+
pg_lsn: "pg_lsn";
|
|
38
|
+
polygon: "polygon";
|
|
39
|
+
real: "real";
|
|
40
|
+
regclass: "regclass";
|
|
41
|
+
regconfig: "regconfig";
|
|
42
|
+
regdictionary: "regdictionary";
|
|
43
|
+
regnamespace: "regnamespace";
|
|
44
|
+
regoper: "regoper";
|
|
45
|
+
regoperator: "regoperator";
|
|
46
|
+
regproc: "regproc";
|
|
47
|
+
regprocedure: "regprocedure";
|
|
48
|
+
regrole: "regrole";
|
|
49
|
+
regtype: "regtype";
|
|
50
|
+
smallint: "smallint";
|
|
51
|
+
smallserial: "smallserial";
|
|
52
|
+
serial: "serial";
|
|
53
|
+
text: "text";
|
|
54
|
+
tid: "tid";
|
|
55
|
+
time: "time";
|
|
56
|
+
time_p: `time(${number})` | `time (${number})`;
|
|
57
|
+
time_with_timezone: "time with time zone";
|
|
58
|
+
time_without_timezone: "time without time zone";
|
|
59
|
+
time_p_with_timezone: `time (${number}) with time zone`;
|
|
60
|
+
time_p_without_timezone: `time (${number}) without time zone`;
|
|
61
|
+
timetz: "timetz";
|
|
62
|
+
timestamp: "timestamp";
|
|
63
|
+
timestamp_p: `timestamp (${number})`;
|
|
64
|
+
timestamp_with_timezone: "timestamp with time zone";
|
|
65
|
+
timestamp_without_timezone: "timestamp without time zone";
|
|
66
|
+
timestamp_p_with_timezone: `timestamp (${number}) with time zone`;
|
|
67
|
+
timestamp_p_without_timezone: `timestamp (${number}) without time zone`;
|
|
68
|
+
timestamptz: "timestamptz";
|
|
69
|
+
tsquery: "tsquery";
|
|
70
|
+
tsrange: "tsrange";
|
|
71
|
+
tstzrange: "tstzrange";
|
|
72
|
+
tsvector: "tsvector";
|
|
73
|
+
txid_snapshot: "txid_snapshot";
|
|
74
|
+
uuid: "uuid";
|
|
75
|
+
varchar: "varchar";
|
|
76
|
+
xid: "xid";
|
|
77
|
+
xml: "xml";
|
|
78
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface OneToManyRelationDefinition {
|
|
2
|
+
type: "1:N";
|
|
3
|
+
model: string;
|
|
4
|
+
fromField: string | string[];
|
|
5
|
+
toField: string | string[];
|
|
6
|
+
}
|
|
7
|
+
export interface ManyToOneRelationDefinition {
|
|
8
|
+
type: "N:1";
|
|
9
|
+
model: string;
|
|
10
|
+
fromField: string | string[];
|
|
11
|
+
toField: string | string[];
|
|
12
|
+
optional?: boolean | null;
|
|
13
|
+
}
|
|
14
|
+
export interface ManyToManyRelationDefinition {
|
|
15
|
+
type: "N:N";
|
|
16
|
+
model: string;
|
|
17
|
+
through: {
|
|
18
|
+
model: string;
|
|
19
|
+
fromRelation: string;
|
|
20
|
+
toRelation: string;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export type RelationDefinition = OneToManyRelationDefinition | ManyToOneRelationDefinition | ManyToManyRelationDefinition;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WARNING!!! The types in this file must be kept in sync
|
|
3
|
+
* with the zod schemas in packages/orm/src/config/defaultZodSchema.ts.
|
|
4
|
+
* If you make a change here, make sure to update the
|
|
5
|
+
* corresponding zod schema.
|
|
6
|
+
*/
|
|
7
|
+
export type DefaultFieldType<DataType extends string> = DataType extends `${infer T extends string}[]` ? DefaultFieldType<T>[] : Uppercase<DataType> extends "BIGINT" | "BIGSERIAL" ? bigint : Uppercase<DataType> extends "DOUBLE PRECISION" | "INTEGER" | "OID" | "REAL" | "SMALLINT" | "SMALLSERIAL" | "SERIAL" ? number : Uppercase<DataType> extends "BPCHAR" | "BIT" | "BOX" | "CIDR" | "CHAR" | "DATERANGE" | "DECIMAL" | "INET" | "INT4RANGE" | "INT8RANGE" | "INT2VECTOR" | "PG_LSN" | "REGCLASS" | "REGCONFIG" | "REGDICTIONARY" | "REGNAMESPACE" | "REGOPER" | "REGOPERATOR" | "REGPROC" | "REGPROCEDURE" | "REGROLE" | "REGTYPE" | "TID" | "XID" | "NUMRANGE" | "TSRANGE" | "TSTZRANGE" | "LINE" | "LSEG" | "MACADDR" | "MACADDR8" | "MONEY" | "PATH" | "POLYGON" | "TEXT" | "TIME" | "TIMETZ" | "TSQUERY" | "TSVECTOR" | "TXID_SNAPSHOT" | "XML" | `BIT${string}` | `CHARACTER${string}` | `NUMERIC${string}` | `TIME ${string}` | `TIME(${string})` | `VARCHAR` | `VARCHAR ${string}` ? string : Uppercase<DataType> extends "BYTEA" ? Buffer : Uppercase<DataType> extends "JSON" | "JSONB" ? unknown : Uppercase<DataType> extends "UUID" ? string : Uppercase<DataType> extends "BOOLEAN" ? boolean : Uppercase<DataType> extends "DATE" | "TIMESTAMP" | "TIMESTAMPTZ" | `TIMESTAMP${string}` ? Date : unknown;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { expectTypeOf, test } from "vitest";
|
|
2
|
+
test("DefaultFieldType", () => {
|
|
3
|
+
expectTypeOf().toBeBigInt();
|
|
4
|
+
expectTypeOf().toBeNumber();
|
|
5
|
+
expectTypeOf().toBeNumber();
|
|
6
|
+
expectTypeOf().toBeNumber();
|
|
7
|
+
expectTypeOf().toBeNumber();
|
|
8
|
+
expectTypeOf().toBeNumber();
|
|
9
|
+
expectTypeOf().toBeNumber();
|
|
10
|
+
expectTypeOf().toBeNumber();
|
|
11
|
+
expectTypeOf().toBeString();
|
|
12
|
+
expectTypeOf().toBeString();
|
|
13
|
+
expectTypeOf().toEqualTypeOf();
|
|
14
|
+
// expectTypeOf<DefaultFieldType<"circle">>().toEqualTypeOf<{
|
|
15
|
+
// x: number;
|
|
16
|
+
// y: number;
|
|
17
|
+
// radius: number;
|
|
18
|
+
// }>();
|
|
19
|
+
// expectTypeOf<DefaultFieldType<"point">>().toEqualTypeOf<{
|
|
20
|
+
// x: number;
|
|
21
|
+
// y: number;
|
|
22
|
+
// }>();
|
|
23
|
+
expectTypeOf().toBeUnknown();
|
|
24
|
+
expectTypeOf().toBeUnknown();
|
|
25
|
+
expectTypeOf().toBeBoolean();
|
|
26
|
+
expectTypeOf().toEqualTypeOf();
|
|
27
|
+
expectTypeOf().toEqualTypeOf();
|
|
28
|
+
// expectTypeOf<DefaultFieldType<"interval">>().toEqualTypeOf<{
|
|
29
|
+
// years?: number;
|
|
30
|
+
// months?: number;
|
|
31
|
+
// days?: number;
|
|
32
|
+
// hours?: number;
|
|
33
|
+
// minutes?: number;
|
|
34
|
+
// seconds?: number;
|
|
35
|
+
// milliseconds?: number;
|
|
36
|
+
// }>();
|
|
37
|
+
expectTypeOf().toEqualTypeOf();
|
|
38
|
+
expectTypeOf().toEqualTypeOf();
|
|
39
|
+
expectTypeOf().toEqualTypeOf();
|
|
40
|
+
expectTypeOf().toBeString();
|
|
41
|
+
expectTypeOf().toBeString();
|
|
42
|
+
expectTypeOf().toBeString();
|
|
43
|
+
expectTypeOf().toBeString();
|
|
44
|
+
expectTypeOf().toBeString();
|
|
45
|
+
expectTypeOf().toBeString();
|
|
46
|
+
expectTypeOf().toBeString();
|
|
47
|
+
expectTypeOf().toBeString();
|
|
48
|
+
expectTypeOf().toBeString();
|
|
49
|
+
expectTypeOf().toBeString();
|
|
50
|
+
expectTypeOf().toBeString();
|
|
51
|
+
expectTypeOf().toBeString();
|
|
52
|
+
expectTypeOf().toBeString();
|
|
53
|
+
expectTypeOf().toBeString();
|
|
54
|
+
expectTypeOf().toBeString();
|
|
55
|
+
expectTypeOf().toBeString();
|
|
56
|
+
expectTypeOf().toBeString();
|
|
57
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("FieldName", () => {
|
|
3
|
+
test("it evaluates to a string union of the model's column names", () => {
|
|
4
|
+
const model = {
|
|
5
|
+
fields: {
|
|
6
|
+
id: { type: "serial" },
|
|
7
|
+
name: { type: "text" },
|
|
8
|
+
createdAt: { type: "timestamp" },
|
|
9
|
+
dateOfBirth: { type: "date" },
|
|
10
|
+
email: { type: "text" },
|
|
11
|
+
type: { type: "text" },
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
expectTypeOf().toEqualTypeOf();
|
|
15
|
+
});
|
|
16
|
+
});
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ModelDefinition } from "#definition/ModelDefinition.js";
|
|
3
|
+
import { DefaultFieldType } from "./DefaultFieldType.js";
|
|
4
|
+
import { FieldName } from "./FieldName.js";
|
|
5
|
+
export type FieldType<Model extends ModelDefinition, C extends FieldName<Model>> = Model["fields"][C]["zodSchema"] extends z.ZodType ? z.infer<Model["fields"][C]["zodSchema"]> | (Model["fields"][C]["nullable"] extends true ? null : never) : DefaultFieldType<Model["fields"][C]["type"]> | (Model["fields"][C]["nullable"] extends true ? null : never);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expectTypeOf } from "vitest";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const user = {
|
|
4
|
+
fields: {
|
|
5
|
+
email: {
|
|
6
|
+
type: "text",
|
|
7
|
+
zodSchema: z.email(),
|
|
8
|
+
},
|
|
9
|
+
id: {
|
|
10
|
+
type: "serial",
|
|
11
|
+
},
|
|
12
|
+
age: {
|
|
13
|
+
type: "integer",
|
|
14
|
+
zodSchema: z.number().min(0).max(150),
|
|
15
|
+
},
|
|
16
|
+
tags: {
|
|
17
|
+
type: "text[]",
|
|
18
|
+
zodSchema: z.array(z.string()),
|
|
19
|
+
},
|
|
20
|
+
status: {
|
|
21
|
+
type: "text",
|
|
22
|
+
zodSchema: z.enum(["active", "inactive", "pending"]),
|
|
23
|
+
},
|
|
24
|
+
createdAt: {
|
|
25
|
+
type: "timestamp with time zone",
|
|
26
|
+
},
|
|
27
|
+
deletedAt: {
|
|
28
|
+
type: "timestamp with time zone",
|
|
29
|
+
zodSchema: z.date().nullable(),
|
|
30
|
+
},
|
|
31
|
+
metadata: {
|
|
32
|
+
type: "jsonb",
|
|
33
|
+
default: "{}",
|
|
34
|
+
zodSchema: z.object({
|
|
35
|
+
foo: z.enum(["a", "b", "c"]),
|
|
36
|
+
bar: z.array(z.object({
|
|
37
|
+
baz: z.enum(["good", "bad", "indifferent"]),
|
|
38
|
+
quux: z.boolean(),
|
|
39
|
+
})),
|
|
40
|
+
}),
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
describe("FieldType", () => {
|
|
45
|
+
describe("json field", () => {
|
|
46
|
+
expectTypeOf().toEqualTypeOf();
|
|
47
|
+
});
|
|
48
|
+
describe("fields with Zod schemas", () => {
|
|
49
|
+
expectTypeOf().toBeString();
|
|
50
|
+
expectTypeOf().toBeNumber();
|
|
51
|
+
expectTypeOf().toEqualTypeOf();
|
|
52
|
+
expectTypeOf().toEqualTypeOf();
|
|
53
|
+
expectTypeOf().toEqualTypeOf();
|
|
54
|
+
});
|
|
55
|
+
describe("fields without Zod schemas (using DefaultFieldType)", () => {
|
|
56
|
+
expectTypeOf().toBeNumber();
|
|
57
|
+
expectTypeOf().toEqualTypeOf();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ModelDefinition } from "../definition/ModelDefinition.js";
|
|
2
|
+
export type FieldWithDefault<Model extends ModelDefinition> = {
|
|
3
|
+
[K in keyof Model["fields"]]: Model["fields"][K]["default"] extends NonNullable<Model["fields"][K]["default"]> ? K : never;
|
|
4
|
+
}[keyof Model["fields"]];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("FieldWithDefault", () => {
|
|
3
|
+
test("extracts just the fields with a default value from the model", () => {
|
|
4
|
+
const user = {
|
|
5
|
+
fields: {
|
|
6
|
+
id: { type: "serial" },
|
|
7
|
+
name: { type: "text", default: "Anonymous" },
|
|
8
|
+
age: { type: "integer", default: 18 },
|
|
9
|
+
email: { type: "text", default: null },
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
expectTypeOf().toEqualTypeOf();
|
|
13
|
+
});
|
|
14
|
+
test("returns never if there are no fields with defaults", () => {
|
|
15
|
+
const user = {
|
|
16
|
+
fields: {
|
|
17
|
+
id: { type: "serial" },
|
|
18
|
+
name: { type: "text" },
|
|
19
|
+
age: { type: "integer" },
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
expectTypeOf().toEqualTypeOf();
|
|
23
|
+
});
|
|
24
|
+
test("excludes fields with null or undefined defaults", () => {
|
|
25
|
+
const user = {
|
|
26
|
+
fields: {
|
|
27
|
+
id: { type: "serial" },
|
|
28
|
+
name: { type: "text", default: "Anonymous" },
|
|
29
|
+
email: { type: "text", default: null },
|
|
30
|
+
phone: { type: "text", default: undefined },
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
expectTypeOf().toEqualTypeOf();
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("ModelName", () => {
|
|
3
|
+
test("it evaluates to a string union of the names of the models", () => {
|
|
4
|
+
const models = {
|
|
5
|
+
user: { fields: {} },
|
|
6
|
+
post: { fields: {} },
|
|
7
|
+
like: { fields: {} },
|
|
8
|
+
comment: { fields: {} },
|
|
9
|
+
mention: { fields: {} },
|
|
10
|
+
color: { fields: {} },
|
|
11
|
+
};
|
|
12
|
+
expectTypeOf().toEqualTypeOf();
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Simplify } from "@casekit/toolbox";
|
|
2
|
+
import { ModelDefinition } from "#definition/ModelDefinition.js";
|
|
3
|
+
import { FieldType } from "./FieldType.js";
|
|
4
|
+
export type ModelType<Model extends ModelDefinition> = Simplify<{
|
|
5
|
+
[C in keyof Model["fields"]]: FieldType<Model, C>;
|
|
6
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, expectTypeOf } from "vitest";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
const user = {
|
|
4
|
+
fields: {
|
|
5
|
+
email: {
|
|
6
|
+
type: "text",
|
|
7
|
+
zodSchema: z.email(),
|
|
8
|
+
},
|
|
9
|
+
id: {
|
|
10
|
+
type: "serial",
|
|
11
|
+
},
|
|
12
|
+
age: {
|
|
13
|
+
type: "integer",
|
|
14
|
+
zodSchema: z.number().min(0).max(150),
|
|
15
|
+
},
|
|
16
|
+
tags: {
|
|
17
|
+
type: "text[]",
|
|
18
|
+
zodSchema: z.array(z.string()),
|
|
19
|
+
},
|
|
20
|
+
status: {
|
|
21
|
+
type: "text",
|
|
22
|
+
zodSchema: z.enum(["active", "inactive", "pending"]),
|
|
23
|
+
},
|
|
24
|
+
createdAt: {
|
|
25
|
+
type: "timestamp with time zone",
|
|
26
|
+
},
|
|
27
|
+
deletedAt: {
|
|
28
|
+
type: "timestamp with time zone",
|
|
29
|
+
zodSchema: z.date().nullable(),
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
describe("ModelType", () => {
|
|
34
|
+
describe("Evaluate to a type containing all the fields of the", () => {
|
|
35
|
+
expectTypeOf().toEqualTypeOf();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("NullableField", () => {
|
|
3
|
+
test("extracts just the nullable fields from the model", () => {
|
|
4
|
+
const user = {
|
|
5
|
+
fields: {
|
|
6
|
+
id: { type: "serial", nullable: false },
|
|
7
|
+
name: { type: "text", nullable: true },
|
|
8
|
+
email: { type: "text", nullable: true },
|
|
9
|
+
age: { type: "integer", nullable: false },
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
expectTypeOf().toEqualTypeOf();
|
|
13
|
+
});
|
|
14
|
+
test("returns never if there are no nullable fields", () => {
|
|
15
|
+
const user = {
|
|
16
|
+
fields: {
|
|
17
|
+
id: { type: "serial", nullable: false },
|
|
18
|
+
name: { type: "text", nullable: false },
|
|
19
|
+
age: { type: "integer", nullable: false },
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
expectTypeOf().toEqualTypeOf();
|
|
23
|
+
});
|
|
24
|
+
test("treats fields without nullable property as non-nullable", () => {
|
|
25
|
+
const user = {
|
|
26
|
+
fields: {
|
|
27
|
+
id: { type: "serial" },
|
|
28
|
+
name: { type: "text", nullable: true },
|
|
29
|
+
age: { type: "integer" },
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
expectTypeOf().toEqualTypeOf();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ModelDefinition } from "#definition/ModelDefinition.js";
|
|
2
|
+
import { FieldName } from "./FieldName.js";
|
|
3
|
+
import { RequiredField } from "./RequiredField.js";
|
|
4
|
+
export type OptionalField<Model extends ModelDefinition> = Exclude<FieldName<Model>, RequiredField<Model>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("OptionalField", () => {
|
|
3
|
+
test("extracts fields that are optional for insert", () => {
|
|
4
|
+
const user = {
|
|
5
|
+
fields: {
|
|
6
|
+
id: { type: "serial", nullable: false },
|
|
7
|
+
name: { type: "text", nullable: false },
|
|
8
|
+
email: { type: "text", nullable: false },
|
|
9
|
+
age: { type: "integer", nullable: false, default: 18 },
|
|
10
|
+
role: { type: "text", nullable: false, provided: true },
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
expectTypeOf().toEqualTypeOf();
|
|
14
|
+
});
|
|
15
|
+
test("returns all fields if none are required", () => {
|
|
16
|
+
const user = {
|
|
17
|
+
fields: {
|
|
18
|
+
id: { type: "serial" },
|
|
19
|
+
name: { type: "text", nullable: true },
|
|
20
|
+
age: { type: "integer", default: 18 },
|
|
21
|
+
role: { type: "text", provided: true },
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
expectTypeOf().toEqualTypeOf();
|
|
25
|
+
});
|
|
26
|
+
test("includes fields with defaults, serial fields, nullable fields and provided fields", () => {
|
|
27
|
+
const user = {
|
|
28
|
+
fields: {
|
|
29
|
+
id: { type: "serial" },
|
|
30
|
+
name: { type: "text", nullable: false },
|
|
31
|
+
email: { type: "text", nullable: true },
|
|
32
|
+
age: { type: "integer", default: 18 },
|
|
33
|
+
role: { type: "text", provided: true },
|
|
34
|
+
score: { type: "integer", nullable: false },
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
expectTypeOf().toEqualTypeOf();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("ProvidedField", () => {
|
|
3
|
+
test("extracts just the provided fields from the model", () => {
|
|
4
|
+
const user = {
|
|
5
|
+
fields: {
|
|
6
|
+
id: { type: "serial", provided: false },
|
|
7
|
+
createdAt: { type: "timestamp", provided: true },
|
|
8
|
+
updatedAt: { type: "timestamp", provided: true },
|
|
9
|
+
name: { type: "text", provided: false },
|
|
10
|
+
},
|
|
11
|
+
};
|
|
12
|
+
expectTypeOf().toEqualTypeOf();
|
|
13
|
+
});
|
|
14
|
+
test("returns never if there are no provided fields", () => {
|
|
15
|
+
const user = {
|
|
16
|
+
fields: {
|
|
17
|
+
id: { type: "serial", provided: false },
|
|
18
|
+
name: { type: "text", provided: false },
|
|
19
|
+
age: { type: "integer", provided: false },
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
expectTypeOf().toEqualTypeOf();
|
|
23
|
+
});
|
|
24
|
+
test("treats fields without provided property as non-provided", () => {
|
|
25
|
+
const user = {
|
|
26
|
+
fields: {
|
|
27
|
+
id: { type: "serial" },
|
|
28
|
+
createdAt: { type: "timestamp", provided: true },
|
|
29
|
+
name: { type: "text" },
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
expectTypeOf().toEqualTypeOf();
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ModelDefinitions } from "#definition/ModelDefinitions.js";
|
|
2
|
+
import { ModelName } from "./ModelName.js";
|
|
3
|
+
import { RelationName } from "./RelationName.js";
|
|
4
|
+
export type RelationModel<Models extends ModelDefinitions, M extends ModelName<Models>, R extends RelationName<Models[M]>> = Models[NonNullable<Models[M]["relations"]>[R]["model"]];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("RelationModel", () => {
|
|
3
|
+
const models = {
|
|
4
|
+
user: {
|
|
5
|
+
fields: {},
|
|
6
|
+
relations: {
|
|
7
|
+
posts: {
|
|
8
|
+
type: "1:N",
|
|
9
|
+
model: "post",
|
|
10
|
+
fromField: "id",
|
|
11
|
+
toField: "authorId",
|
|
12
|
+
},
|
|
13
|
+
likedPosts: {
|
|
14
|
+
type: "N:N",
|
|
15
|
+
model: "post",
|
|
16
|
+
through: {
|
|
17
|
+
model: "like",
|
|
18
|
+
fromRelation: "user",
|
|
19
|
+
toRelation: "post",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
post: {
|
|
25
|
+
fields: {},
|
|
26
|
+
relations: {
|
|
27
|
+
author: {
|
|
28
|
+
type: "N:1",
|
|
29
|
+
model: "user",
|
|
30
|
+
fromField: "authorId",
|
|
31
|
+
toField: "id",
|
|
32
|
+
},
|
|
33
|
+
likes: {
|
|
34
|
+
type: "1:N",
|
|
35
|
+
model: "like",
|
|
36
|
+
fromField: "id",
|
|
37
|
+
toField: "postId",
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
like: { fields: {} },
|
|
42
|
+
};
|
|
43
|
+
test("looks up the correct relation model in the schema for N:1 relations", () => {
|
|
44
|
+
expectTypeOf().toExtend();
|
|
45
|
+
});
|
|
46
|
+
test("looks up the correct relation model in the schema for 1:N relations", () => {
|
|
47
|
+
expectTypeOf().toExtend();
|
|
48
|
+
});
|
|
49
|
+
test("looks up the correct relation model in the schema for N:N relations", () => {
|
|
50
|
+
expectTypeOf().toExtend();
|
|
51
|
+
});
|
|
52
|
+
describe("errors", () => {
|
|
53
|
+
test("looking up a non-existing relation causes an error", () => {
|
|
54
|
+
expectTypeOf().not.toExtend();
|
|
55
|
+
});
|
|
56
|
+
test("looking up a relation for a model that doesn't exist causes an error", () => {
|
|
57
|
+
expectTypeOf().not.toExtend();
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("RelationName", () => {
|
|
3
|
+
test("it evaluates to a string union of the names of the model's relations", () => {
|
|
4
|
+
const user = {
|
|
5
|
+
fields: { id: { type: "serial" } },
|
|
6
|
+
relations: {
|
|
7
|
+
posts: {
|
|
8
|
+
type: "1:N",
|
|
9
|
+
model: "post",
|
|
10
|
+
fromField: "id",
|
|
11
|
+
toField: "authorId",
|
|
12
|
+
},
|
|
13
|
+
friends: {
|
|
14
|
+
type: "N:N",
|
|
15
|
+
model: "user",
|
|
16
|
+
through: {
|
|
17
|
+
model: "friendship",
|
|
18
|
+
fromRelation: "user",
|
|
19
|
+
toRelation: "friend",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
expectTypeOf().toEqualTypeOf();
|
|
25
|
+
const post = {
|
|
26
|
+
fields: { id: { type: "serial" } },
|
|
27
|
+
relations: {
|
|
28
|
+
author: {
|
|
29
|
+
type: "N:1",
|
|
30
|
+
model: "user",
|
|
31
|
+
fromField: "authorId",
|
|
32
|
+
toField: "id",
|
|
33
|
+
},
|
|
34
|
+
likes: {
|
|
35
|
+
type: "1:N",
|
|
36
|
+
model: "like",
|
|
37
|
+
fromField: "id",
|
|
38
|
+
toField: "postId",
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
expectTypeOf().toEqualTypeOf();
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ModelDefinition } from "#definition/ModelDefinition.js";
|
|
2
|
+
import { FieldName } from "./FieldName.js";
|
|
3
|
+
import { FieldWithDefault } from "./FieldWithDefault.js";
|
|
4
|
+
import { NullableField } from "./NullableField.js";
|
|
5
|
+
import { ProvidedField } from "./ProvidedField.js";
|
|
6
|
+
import { SerialField } from "./SerialField.js";
|
|
7
|
+
export type RequiredField<Model extends ModelDefinition> = Exclude<FieldName<Model>, NullableField<Model> | FieldWithDefault<Model> | SerialField<Model> | ProvidedField<Model>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("RequiredField", () => {
|
|
3
|
+
test("extracts fields that are required for insert", () => {
|
|
4
|
+
const user = {
|
|
5
|
+
fields: {
|
|
6
|
+
id: { type: "serial", nullable: false },
|
|
7
|
+
name: { type: "text", nullable: false },
|
|
8
|
+
email: { type: "text", nullable: false },
|
|
9
|
+
age: { type: "integer", nullable: false, default: 18 },
|
|
10
|
+
role: { type: "text", nullable: false, provided: true },
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
expectTypeOf().toEqualTypeOf();
|
|
14
|
+
});
|
|
15
|
+
test("returns never if all fields are optional", () => {
|
|
16
|
+
const user = {
|
|
17
|
+
fields: {
|
|
18
|
+
id: { type: "serial" },
|
|
19
|
+
name: { type: "text", nullable: true },
|
|
20
|
+
age: { type: "integer", default: 18 },
|
|
21
|
+
role: { type: "text", provided: true },
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
expectTypeOf().toEqualTypeOf();
|
|
25
|
+
});
|
|
26
|
+
test("excludes fields with defaults, serial fields, nullable fields and provided fields", () => {
|
|
27
|
+
const user = {
|
|
28
|
+
fields: {
|
|
29
|
+
id: { type: "serial" },
|
|
30
|
+
name: { type: "text", nullable: false },
|
|
31
|
+
email: { type: "text", nullable: true },
|
|
32
|
+
age: { type: "integer", default: 18 },
|
|
33
|
+
role: { type: "text", provided: true },
|
|
34
|
+
score: { type: "integer", nullable: false },
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
expectTypeOf().toEqualTypeOf();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ModelDefinition } from "../definition/ModelDefinition.js";
|
|
2
|
+
export type SerialField<Model extends ModelDefinition> = {
|
|
3
|
+
[K in keyof Model["fields"]]: Uppercase<Model["fields"][K]["type"]> extends "SMALLSERIAL" | "SERIAL" | "BIGSERIAL" ? K : never;
|
|
4
|
+
}[keyof Model["fields"]];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { describe, expectTypeOf, test } from "vitest";
|
|
2
|
+
describe("SerialField", () => {
|
|
3
|
+
test("extracts just the fields with a SERIAL datatype from the model", () => {
|
|
4
|
+
const user = {
|
|
5
|
+
fields: {
|
|
6
|
+
id: { type: "serial" },
|
|
7
|
+
smallId: { type: "smallserial" },
|
|
8
|
+
bigId: { type: "bigserial" },
|
|
9
|
+
name: { type: "text" },
|
|
10
|
+
age: { type: "integer" },
|
|
11
|
+
},
|
|
12
|
+
};
|
|
13
|
+
expectTypeOf().toEqualTypeOf();
|
|
14
|
+
});
|
|
15
|
+
test("works for both lower and uppercase field types", () => {
|
|
16
|
+
const user = {
|
|
17
|
+
fields: {
|
|
18
|
+
id: { type: "SERIAL" },
|
|
19
|
+
smallId: { type: "SMALLSERIAL" },
|
|
20
|
+
bigId: { type: "BIGSERIAL" },
|
|
21
|
+
name: { type: "TEXT" },
|
|
22
|
+
age: { type: "INTEGER" },
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
expectTypeOf().toEqualTypeOf();
|
|
26
|
+
});
|
|
27
|
+
test("returns never if there are no SERIAL fields", () => {
|
|
28
|
+
const user = {
|
|
29
|
+
fields: {
|
|
30
|
+
name: { type: "text" },
|
|
31
|
+
age: { type: "integer" },
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
expectTypeOf().toEqualTypeOf();
|
|
35
|
+
});
|
|
36
|
+
test("does not include fields with a type that end with serial but isn't a serial type", () => {
|
|
37
|
+
const user = {
|
|
38
|
+
fields: {
|
|
39
|
+
id: { type: "serial" },
|
|
40
|
+
name: { type: "text" },
|
|
41
|
+
age: { type: "integer" },
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
expectTypeOf().toEqualTypeOf();
|
|
45
|
+
});
|
|
46
|
+
});
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export type { FieldDefinition } from "./definition/FieldDefinition.js";
|
|
2
|
+
export type { ForeignKeyDefinition } from "./definition/ForeignKeyDefinition.js";
|
|
3
|
+
export type { ModelDefinition } from "./definition/ModelDefinition.js";
|
|
4
|
+
export type { ModelDefinitions } from "./definition/ModelDefinitions.js";
|
|
5
|
+
export type { OperatorDefinitions } from "./definition/OperatorDefinitions.js";
|
|
6
|
+
export type { PostgresDataTypes } from "./definition/PostgresDataTypes.js";
|
|
7
|
+
export type { ManyToManyRelationDefinition, ManyToOneRelationDefinition, OneToManyRelationDefinition, RelationDefinition, } from "./definition/RelationDefinition.js";
|
|
8
|
+
export type { RelationDefinitions } from "./definition/RelationDefinitions.js";
|
|
9
|
+
export type { UniqueConstraintDefinition } from "./definition/UniqueConstraintDefinition.js";
|
|
10
|
+
export type { WhereOperatorDefinition as OperatorDefinition } from "./definition/WhereOperator.js";
|
|
11
|
+
export type { DefaultFieldType } from "./helper/DefaultFieldType.js";
|
|
12
|
+
export type { FieldName } from "./helper/FieldName.js";
|
|
13
|
+
export type { FieldType } from "./helper/FieldType.js";
|
|
14
|
+
export type { FieldWithDefault } from "./helper/FieldWithDefault.js";
|
|
15
|
+
export type { ModelName } from "./helper/ModelName.js";
|
|
16
|
+
export type { ModelType } from "./helper/ModelType.js";
|
|
17
|
+
export type { NullableField } from "./helper/NullableField.js";
|
|
18
|
+
export type { OptionalField } from "./helper/OptionalField.js";
|
|
19
|
+
export type { ProvidedField } from "./helper/ProvidedField.js";
|
|
20
|
+
export type { RelationModel } from "./helper/RelationModel.js";
|
|
21
|
+
export type { RelationName } from "./helper/RelationName.js";
|
|
22
|
+
export type { RequiredField } from "./helper/RequiredField.js";
|
|
23
|
+
export type { SerialField } from "./helper/SerialField.js";
|
|
24
|
+
export type { Config } from "./Config.js";
|
|
25
|
+
export type { Logger } from "./Logger.js";
|
package/build/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@casekit/orm-schema",
|
|
3
|
+
"description": "",
|
|
4
|
+
"version": "0.0.1-release-candidate",
|
|
5
|
+
"author": "",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"@casekit/sql": "0.0.1-release-candidate",
|
|
8
|
+
"@casekit/toolbox": "0.0.1-release-candidate"
|
|
9
|
+
},
|
|
10
|
+
"devDependencies": {
|
|
11
|
+
"@trivago/prettier-plugin-sort-imports": "^5.2.2",
|
|
12
|
+
"@types/node": "^24.0.3",
|
|
13
|
+
"@types/pg": "^8.15.4",
|
|
14
|
+
"@types/uuid": "^10.0.0",
|
|
15
|
+
"prettier": "^3.5.3",
|
|
16
|
+
"ts-essentials": "^10.1.1",
|
|
17
|
+
"typescript": "^5.8.3",
|
|
18
|
+
"typescript-eslint": "^8.34.1",
|
|
19
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
20
|
+
"vitest": "^3.2.4",
|
|
21
|
+
"@casekit/tsconfig": "0.0.1-release-candidate",
|
|
22
|
+
"@casekit/prettier-config": "0.0.1-release-candidate"
|
|
23
|
+
},
|
|
24
|
+
"exports": {
|
|
25
|
+
".": "./build/index.js"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"/build"
|
|
29
|
+
],
|
|
30
|
+
"imports": {
|
|
31
|
+
"#*": "./build/*"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [],
|
|
34
|
+
"license": "ISC",
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"pg": "^8.13.1",
|
|
37
|
+
"zod": "^4.0.17"
|
|
38
|
+
},
|
|
39
|
+
"prettier": "@casekit/prettier-config",
|
|
40
|
+
"type": "module",
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "rm -rf ./build && tsc",
|
|
43
|
+
"format:check": "prettier --check .",
|
|
44
|
+
"format": "prettier --write .",
|
|
45
|
+
"lint": "eslint src --max-warnings 0",
|
|
46
|
+
"test": "vitest --run --typecheck",
|
|
47
|
+
"test:watch": "vitest --typecheck",
|
|
48
|
+
"typecheck": "tsc --noEmit"
|
|
49
|
+
}
|
|
50
|
+
}
|