@ez4/database 0.27.0 → 0.29.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.
@@ -7,7 +7,7 @@ import type { OrderModeUtils } from './order';
7
7
  import type { LockModeUtils } from './lock';
8
8
  import type { TableMetadata } from './table';
9
9
  import type { Database } from './database';
10
- import type { AnyObject, PartialProperties, PartialObject, FlatObject, OptionalObject, StrictObject, IsNullable, IsObjectEmpty, IsObject, IsArray, Prettify } from '@ez4/utils';
10
+ import type { AnyObject, PartialProperties, PartialObject, FlatObject, OptionalObject, StrictObject, IsNullable, IsUndefined, IsObjectEmpty, IsObject, IsArray, Prettify } from '@ez4/utils';
11
11
  /**
12
12
  * Query builder types.
13
13
  */
@@ -84,8 +84,8 @@ export declare namespace Query {
84
84
  export type Record<S extends AnyObject, T extends TableMetadata> = PartialObject<SelectOutputFields<T['schema'], T['relations']>, S>;
85
85
  export type SelectInput<T extends TableMetadata> = PartialProperties<SelectInputFields<T['schema'], T['relations']>>;
86
86
  export type StrictSelectInput<S extends AnyObject, T extends TableMetadata> = StrictObject<S, SelectInputFields<T['schema'], T['relations']>>;
87
- export type InsertDataInput<T extends TableMetadata> = IsObjectEmpty<T['relations']['changes']> extends false ? Omit<T['schema'] & T['relations']['changes'], T['relations']['indexes']> : T['schema'];
88
- export type UpdateDataInput<T extends TableMetadata> = AtomicDataInput<IsObjectEmpty<T['relations']['changes']> extends false ? Omit<T['schema'] & FlatObject<T['relations']['changes']>, T['relations']['indexes']> : T['schema']>;
87
+ export type InsertDataInput<T extends TableMetadata> = IsObjectEmpty<T['relations']['inserts']> extends false ? Omit<T['schema'], T['relations']['indexes']> & T['relations']['inserts'] : T['schema'];
88
+ export type UpdateDataInput<T extends TableMetadata> = IsObjectEmpty<T['relations']['updates']> extends false ? AtomicDataInput<Omit<T['schema'], T['relations']['indexes']> & FlatObject<T['relations']['updates']>> : AtomicDataInput<T['schema']>;
89
89
  export type OrderInput<T extends TableMetadata> = OrderModeUtils.Input<T>;
90
90
  export type StrictIncludeInput<S extends AnyObject, T extends TableMetadata> = IsObjectEmpty<T['relations']['filters']> extends true ? never : {
91
91
  [P in keyof T['relations']['filters']]?: P extends keyof S ? StrictIncludeRelation<NonNullable<T['relations']['filters'][P]>, T['engine']> : never;
@@ -167,10 +167,10 @@ export declare namespace Query {
167
167
  type AtomicDataInput<T extends AnyObject> = AtomicRequiredFields<T> & AtomicOptionalFields<T>;
168
168
  type AtomicDataField<T> = T extends number ? AtomicOperation | T : T extends AnyObject ? AtomicDataInput<T> : NonNullable<T> extends AnyObject ? null | AtomicDataInput<NonNullable<T>> : T;
169
169
  type AtomicRequiredFields<T extends AnyObject> = {
170
- [P in keyof T as T[P] extends undefined ? never : P]: AtomicDataField<T[P]>;
170
+ [P in keyof T as IsUndefined<T[P]> extends true ? never : P]: AtomicDataField<T[P]>;
171
171
  };
172
172
  type AtomicOptionalFields<T extends AnyObject> = {
173
- [P in keyof T as T[P] extends undefined ? P : never]?: AtomicDataField<T[P]>;
173
+ [P in keyof T as IsUndefined<T[P]> extends true ? P : never]?: AtomicDataField<T[P]>;
174
174
  };
175
175
  type AtomicOperation = AtomicIncrement | AtomicDecrement | AtomicMultiply | AtomicDivide;
176
176
  type AtomicIncrement = {
@@ -1,4 +1,4 @@
1
- import type { AnyObject, ArrayRest, PropertyType, ExclusiveType, IsArrayEmpty, IsUndefined, FlatObject, MergeObject } from '@ez4/utils';
1
+ import type { AnyObject, ArrayRest, PropertyType, ExclusiveType, IsArrayEmpty, IsUndefined, MergeObject, Prettify } from '@ez4/utils';
2
2
  import type { IndexedTables, PrimaryIndexes, UniqueIndexes } from './indexes';
3
3
  import type { Database, DatabaseTables } from './database';
4
4
  import type { TableSchemas } from './schemas';
@@ -7,8 +7,9 @@ import type { TableSchemas } from './schemas';
7
7
  */
8
8
  export type RelationMetadata = {
9
9
  filters: Record<string, AnyObject | undefined>;
10
+ updates: Record<string, AnyObject | undefined>;
11
+ inserts: Record<string, AnyObject | undefined>;
10
12
  selects: Record<string, AnyObject | undefined>;
11
- changes: Record<string, AnyObject | undefined>;
12
13
  records: Record<string, AnyObject | undefined>;
13
14
  indexes: string;
14
15
  };
@@ -45,73 +46,124 @@ type TableRelation<T extends Database.Table[], C extends Database.Table, S exten
45
46
  relations: infer R;
46
47
  } ? N extends string ? R extends AnyObject ? {
47
48
  [P in N]: {
48
- indexes: RelationIndexes<PropertyType<N, I>, R>;
49
+ indexes: RelationIndexes<N, I, R>;
49
50
  filters: FilterableRelationSchemas<S, R>;
50
- changes: RequiredRelationSchemas<PropertyType<N, S>, S, I, R, true> & OptionalRelationSchemas<PropertyType<N, S>, S, I, R, true>;
51
- selects: FlatObject<RequiredRelationSchemas<PropertyType<N, S>, S, I, R, false>> & FlatObject<OptionalRelationSchemas<PropertyType<N, S>, S, I, R, false>> & NestedRelationSelects<T, S, I, R>;
52
- records: MergeObject<RequiredRelationSchemas<PropertyType<N, S>, S, I, R, false> & OptionalRelationSchemas<PropertyType<N, S>, S, I, R, false>, NestedRelationRecords<T, S, I, R>>;
51
+ updates: UpdateRelationSchemas<N, S, I, R>;
52
+ inserts: InsertRelationSchemas<N, PropertyType<N, S>, S, I, R>;
53
+ selects: SelectRelationSchemas<S, I, R> & NestedSelectRelationSchemas<T, S, I, R>;
54
+ records: MergeObject<RecordsRelationSchemas<PropertyType<N, S>, S, I, R>, NestedRecordsRelationSchemas<T, S, I, R>>;
53
55
  };
54
56
  } : {} : {} : {};
57
+ /**
58
+ * Check whether the given column is a primary index.
59
+ */
60
+ type IsPrimarySourceIndex<C, I extends Record<string, Database.Indexes>> = RelationSourceColumn<C> extends keyof PrimaryIndexes<PropertyType<RelationSourceTable<C>, I>> ? true : false;
61
+ /**
62
+ * Check whether the given column is a unique index.
63
+ */
64
+ type IsUniqueSourceIndex<C, I extends Record<string, Database.Indexes>> = RelationSourceColumn<C> extends keyof UniqueIndexes<PropertyType<RelationSourceTable<C>, I>> ? true : false;
65
+ /**
66
+ * Check whether the given column is a primary target index.
67
+ */
68
+ type IsPrimaryTargetIndex<V, I extends Database.Indexes> = RelationTargetColumn<V> extends keyof PrimaryIndexes<I> ? true : false;
69
+ /**
70
+ * Check whether the given column is a unique target index.
71
+ */
72
+ export type IsUniqueTargetIndex<V, I extends Database.Indexes> = RelationTargetColumn<V> extends keyof UniqueIndexes<I> ? true : false;
73
+ /**
74
+ * Check whether the given column is a secondary target index.
75
+ */
76
+ type IsSecondaryTargetIndex<V, I extends Database.Indexes> = RelationTargetColumn<V> extends keyof (PrimaryIndexes<I> & UniqueIndexes<I>) ? false : true;
77
+ /**
78
+ * Check whether a relation is optional or not.
79
+ */
80
+ type IsOptionalRelation<C, V, T extends Database.Schema, I extends Record<string, Database.Indexes>, E extends boolean> = IsPrimarySourceIndex<C, I> extends true ? IsUndefined<PropertyType<RelationTargetColumn<V>, T>> : IsUniqueSourceIndex<C, I> extends true ? true : E;
55
81
  /**
56
82
  * Produce an object containing all relation indexes.
57
83
  */
58
- type RelationIndexes<I extends Database.Indexes, R extends AnyObject> = keyof {
59
- [C in keyof R as RelationTargetColumn<C> extends keyof PrimaryIndexes<I> ? never : RelationTargetColumn<C>]: never;
84
+ type RelationIndexes<N, I extends Record<string, Database.Indexes>, R extends AnyObject> = keyof {
85
+ [P in keyof R as IsRelationIndex<N, R[P], P, I> extends true ? RelationTargetColumn<P> : never]: never;
60
86
  };
61
87
  /**
62
- * Produce an object containing all filterable relation schemas.
88
+ * Check whether the given source and target columns are used to index the relation.
89
+ */
90
+ type IsRelationIndex<N, C, V, I extends Record<string, Database.Indexes>> = IsPrimarySourceIndex<C, I> extends false ? IsSecondaryTargetIndex<V, PropertyType<N, I>> extends false ? IsUniqueTargetIndex<V, PropertyType<N, I>> extends true ? IsUniqueSourceIndex<C, I> : false : true : true;
91
+ /**
92
+ * Produce an object containing relation schemas for filters.
63
93
  */
64
94
  type FilterableRelationSchemas<S extends Record<string, Database.Schema>, R extends AnyObject> = {
65
- [C in keyof R as RelationTargetAlias<C>]: Omit<PropertyType<RelationSourceTable<R[C]>, S>, RelationSourceColumn<R[C]>>;
95
+ [P in keyof R as RelationTargetAlias<P>]: Omit<PropertyType<RelationSourceTable<R[P]>, S>, RelationSourceColumn<R[P]>>;
96
+ };
97
+ /**
98
+ * Produce an object containing relation schemas for updates.
99
+ */
100
+ type UpdateRelationSchemas<N, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject> = {
101
+ [P in keyof R as RelationTargetAlias<P>]?: ChangeRelationSchema<N, R[P], P, S, I>;
66
102
  };
67
103
  /**
68
- * Produce an object containing only required relation schemas.
104
+ * Produce an object containing relation schemas for inserts.
69
105
  */
70
- type RequiredRelationSchemas<T extends Database.Schema, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject, E extends boolean> = {
71
- [C in keyof R as IsOptionalRelation<R[C], C, T, I, E> extends false ? RelationTargetAlias<C> : never]: RelationSchema<R[C], C, T, S, I, E>;
106
+ type InsertRelationSchemas<N, T extends Database.Schema, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject> = {
107
+ [P in keyof R as IsOptionalRelation<R[P], P, T, I, true> extends true ? RelationTargetAlias<P> : never]?: ChangeRelationSchema<N, R[P], P, S, I>;
108
+ } & {
109
+ [P in keyof R as IsOptionalRelation<R[P], P, T, I, true> extends false ? RelationTargetAlias<P> : never]: ChangeRelationSchema<N, R[P], P, S, I>;
72
110
  };
73
111
  /**
74
- * Produce an object containing only optional relation schemas.
112
+ * Produce an object containing relation schemas for selects.
75
113
  */
76
- type OptionalRelationSchemas<T extends Database.Schema, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject, E extends boolean> = {
77
- [C in keyof R as IsOptionalRelation<R[C], C, T, I, E> extends true ? RelationTargetAlias<C> : never]?: RelationSchema<R[C], C, T, S, I, E>;
114
+ type SelectRelationSchemas<S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject> = {
115
+ [P in keyof R as RelationTargetAlias<P>]?: SelectRelationSchema<R[P], S, I>;
116
+ };
117
+ /**
118
+ * Produce an object containing relation schemas for records.
119
+ */
120
+ type RecordsRelationSchemas<T extends Database.Schema, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject> = {
121
+ [P in keyof R as IsOptionalRelation<R[P], P, T, I, false> extends true ? RelationTargetAlias<P> : never]?: RecordRelationSchema<R[P], S, I>;
122
+ } & {
123
+ [P in keyof R as IsOptionalRelation<R[P], P, T, I, false> extends false ? RelationTargetAlias<P> : never]: RecordRelationSchema<R[P], S, I>;
78
124
  };
79
125
  /**
80
126
  * Produce an object containing all nested relation schemas for select operations.
81
127
  */
82
- type NestedRelationSelects<T extends Database.Table[], S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject> = {
83
- [C in keyof R as RelationTargetAlias<C>]?: RelationSourceTable<R[C]> extends keyof MergeRelations<T, T, S, I> ? MergeRelations<T, T, S, I>[RelationSourceTable<R[C]>] extends {
128
+ type NestedSelectRelationSchemas<T extends Database.Table[], S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject> = {
129
+ [P in keyof R as RelationTargetAlias<P>]?: RelationSourceTable<R[P]> extends keyof MergeRelations<T, T, S, I> ? MergeRelations<T, T, S, I>[RelationSourceTable<R[P]>] extends {
84
130
  selects: infer N;
85
131
  } ? N : never : never;
86
132
  };
87
133
  /**
88
134
  * Produce an object containing all nested relation schemas for records.
89
135
  */
90
- type NestedRelationRecords<T extends Database.Table[], S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject> = {
91
- [C in keyof R as RelationTargetAlias<C>]?: RelationSourceTable<R[C]> extends keyof MergeRelations<T, T, S, I> ? MergeRelations<T, T, S, I>[RelationSourceTable<R[C]>] extends {
136
+ type NestedRecordsRelationSchemas<T extends Database.Table[], S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, R extends AnyObject> = {
137
+ [P in keyof R as RelationTargetAlias<P>]?: RelationSourceTable<R[P]> extends keyof MergeRelations<T, T, S, I> ? MergeRelations<T, T, S, I>[RelationSourceTable<R[P]>] extends {
92
138
  records: infer N;
93
139
  } ? N : never : never;
94
140
  };
95
141
  /**
96
- * Check whether a relation is optional or not.
142
+ * Produce a type corresponding to the source column schema.
143
+ */
144
+ type SourceColumnSchema<C, S extends Record<string, Database.Schema>> = PropertyType<RelationSourceTable<C>, S>;
145
+ /**
146
+ * Produce a change relation schema according to its indexation.
97
147
  */
98
- type IsOptionalRelation<C, V, T extends Database.Schema, I extends Record<string, Database.Indexes>, E extends boolean> = RelationSourceColumn<C> extends keyof PrimaryIndexes<PropertyType<RelationSourceTable<C>, I>> ? IsUndefined<PropertyType<RelationTargetColumn<V>, T>> : RelationSourceColumn<C> extends keyof UniqueIndexes<PropertyType<RelationSourceTable<C>, I>> ? true : E;
148
+ type ChangeRelationSchema<N, C, V, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>> = IsPrimarySourceIndex<C, I> extends true ? ExclusiveType<SourceColumnSchema<C, S>, PrimaryKeyConnectionSchema<C, S, I>> : IsUniqueSourceIndex<C, I> extends true ? IsPrimaryTargetIndex<V, PropertyType<N, I>> extends true ? ExclusiveType<Omit<SourceColumnSchema<C, S>, RelationSourceColumn<C>>, UniqueKeyConnectionSchema<C, S, I>> : ExclusiveType<SourceColumnSchema<C, S>, UniqueKeyConnectionSchema<C, S, I>> : ExclusiveType<Omit<SourceColumnSchema<C, S>, RelationSourceColumn<C>>, PrimaryKeyConnectionSchema<C, S, I>>[];
99
149
  /**
100
- * Check whether a column is primary.
150
+ * Produce a select relation schema according to its indexation.
101
151
  */
102
- type IsPrimaryIndex<C, I extends Record<string, Database.Indexes>> = RelationSourceColumn<C> extends keyof PrimaryIndexes<PropertyType<RelationSourceTable<C>, I>> ? true : false;
152
+ type SelectRelationSchema<C, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>> = IsPrimarySourceIndex<C, I> extends true ? SourceColumnSchema<C, S> : IsUniqueSourceIndex<C, I> extends true ? SourceColumnSchema<C, S> : SourceColumnSchema<C, S>;
103
153
  /**
104
- * Check whether a column is unique.
154
+ * Produce a record relation schema according to its indexation.
105
155
  */
106
- type IsUniqueIndex<C, I extends Record<string, Database.Indexes>> = RelationSourceColumn<C> extends keyof UniqueIndexes<PropertyType<RelationSourceTable<C>, I>> ? true : false;
156
+ type RecordRelationSchema<C, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>> = IsPrimarySourceIndex<C, I> extends true ? SourceColumnSchema<C, S> : IsUniqueSourceIndex<C, I> extends true ? SourceColumnSchema<C, S> : SourceColumnSchema<C, S>[];
107
157
  /**
108
- * Produce a type corresponding to the source index column type.
158
+ * Produce a relation schema for connections using primary keys.
109
159
  */
110
- type ExtractSourceIndexType<C, S extends Record<string, Database.Schema>> = PropertyType<RelationSourceTable<C>, S>;
160
+ type PrimaryKeyConnectionSchema<C, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>> = Prettify<{
161
+ [P in keyof PrimaryIndexes<PropertyType<RelationSourceTable<C>, I>>]: PropertyType<P, PropertyType<RelationSourceTable<C>, S>> | undefined | null;
162
+ }>;
111
163
  /**
112
- * Produce a relation schema according to its indexation.
164
+ * Produce a relation schema for connections using unique keys.
113
165
  */
114
- type RelationSchema<C, V, T extends Database.Schema, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>, E extends boolean> = IsPrimaryIndex<C, I> extends true ? E extends false ? ExtractSourceIndexType<C, S> : ExclusiveType<ExtractSourceIndexType<C, S>, {
115
- [P in RelationTargetColumn<V>]: PropertyType<RelationTargetColumn<V>, T>;
116
- }> : IsUniqueIndex<C, I> extends true ? E extends false ? ExtractSourceIndexType<C, S> : Omit<ExtractSourceIndexType<C, S>, RelationSourceColumn<C>> : Omit<ExtractSourceIndexType<C, S>, RelationSourceColumn<C>>[];
166
+ type UniqueKeyConnectionSchema<C, S extends Record<string, Database.Schema>, I extends Record<string, Database.Indexes>> = Prettify<{
167
+ [P in keyof UniqueIndexes<PropertyType<RelationSourceTable<C>, I>> as P extends RelationSourceColumn<C> ? P : never]: PropertyType<P, PropertyType<RelationSourceTable<C>, S>> | undefined | null;
168
+ }>;
117
169
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ez4/database",
3
3
  "description": "EZ4: Components to build database services",
4
- "version": "0.27.0",
4
+ "version": "0.29.0",
5
5
  "author": "Silas B.",
6
6
  "license": "MIT",
7
7
  "type": "module",
@@ -36,16 +36,16 @@
36
36
  "lint": "eslint --cache",
37
37
  "clean": "rm -f *.tsbuildinfo && rm -rf dist/*",
38
38
  "build": "tsc && node tools/bundler.mjs",
39
- "test": "npm run build && ez4 test",
39
+ "test": "npm run build && tsc -p tsconfig.test.json && ez4 test",
40
40
  "local:publish": "npm run build && npm run clean:registry && npm publish --registry http://localhost:4873",
41
41
  "clean:registry": "rm -rf ../../.registry/@ez4/database",
42
42
  "live:publish": "npm run build && npm publish --access public"
43
43
  },
44
44
  "dependencies": {
45
- "@ez4/common": "^0.27.0",
46
- "@ez4/project": "^0.27.0",
47
- "@ez4/reflection": "^0.27.0",
48
- "@ez4/schema": "^0.27.0",
49
- "@ez4/utils": "^0.27.0"
45
+ "@ez4/common": "^0.29.0",
46
+ "@ez4/project": "^0.29.0",
47
+ "@ez4/reflection": "^0.29.0",
48
+ "@ez4/schema": "^0.29.0",
49
+ "@ez4/utils": "^0.29.0"
50
50
  }
51
51
  }