kysely-hydrate 0.2.1 → 0.3.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.
- package/README.md +180 -9
- package/dist/index.d.mts +169 -183
- package/dist/index.mjs +81 -141
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -138,6 +138,7 @@ By design, Kysely has the following constraints:
|
|
|
138
138
|
- [Mapped properties with `.mapFields()`](#mapped-properties-with-mapfields)
|
|
139
139
|
- [Computed properties with `.extras()`](#computed-properties-with-extras)
|
|
140
140
|
- [Excluded properties with `.omit()`](#excluded-properties-with-omit)
|
|
141
|
+
- [Output transformations with `.map()`](#output-transformations-with-map)
|
|
141
142
|
- [Composable mappings with `.with()`](#composable-mappings-with-with)
|
|
142
143
|
- [Execution](#execution)
|
|
143
144
|
- [Hydrators](#hydrators)
|
|
@@ -146,6 +147,7 @@ By design, Kysely has the following constraints:
|
|
|
146
147
|
- [Selecting and mapping fields with `.fields()`](#selecting-and-mapping-fields-with-fields)
|
|
147
148
|
- [Computed properties with `.extras()`](#computed-properties-with-extras-1)
|
|
148
149
|
- [Excluding fields with `.omit()`](#excluding-fields-with-omit)
|
|
150
|
+
- [Output transformations with `.map()`](#output-transformations-with-map-1)
|
|
149
151
|
- [Attached collections with `.attach*()`](#attached-collections-with-attach)
|
|
150
152
|
- [Prefixed collections with `.has*()`](#prefixed-collections-with-has)
|
|
151
153
|
- [Composing hydrators with `.extend()`](#composing-hydrators-with-extend)
|
|
@@ -779,6 +781,134 @@ const users = await hydrate(
|
|
|
779
781
|
type Result = Array<{ id: number; fullName: string }>;
|
|
780
782
|
```
|
|
781
783
|
|
|
784
|
+
### Output transformations with `.map()`
|
|
785
|
+
|
|
786
|
+
The `.map()` method transforms the hydrated output into a different shape. Use
|
|
787
|
+
it for complex transformations like:
|
|
788
|
+
|
|
789
|
+
- Converting plain objects into class instances
|
|
790
|
+
- Asserting discriminated union types
|
|
791
|
+
- Restructuring or reshaping data
|
|
792
|
+
|
|
793
|
+
Unlike `.mapFields()` and `.extras()`, which operate on individual fields,
|
|
794
|
+
`.map()` receives the complete hydrated result and can transform it however you
|
|
795
|
+
want.
|
|
796
|
+
|
|
797
|
+
```ts
|
|
798
|
+
// Transform into class instances
|
|
799
|
+
class UserModel {
|
|
800
|
+
constructor(
|
|
801
|
+
public id: number,
|
|
802
|
+
public name: string,
|
|
803
|
+
) {}
|
|
804
|
+
|
|
805
|
+
getDisplayName() {
|
|
806
|
+
return `User: ${this.name}`;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
const users = await hydrate(
|
|
811
|
+
db.selectFrom("users").select(["users.id", "users.name"]),
|
|
812
|
+
)
|
|
813
|
+
.map((user) => new UserModel(user.id, user.name))
|
|
814
|
+
.execute();
|
|
815
|
+
// ⬇
|
|
816
|
+
type Result = UserModel[];
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
#### Chaining transformations
|
|
820
|
+
|
|
821
|
+
You can chain multiple `.map()` calls to compose transformations. Each function
|
|
822
|
+
receives the output of the previous transformation.
|
|
823
|
+
|
|
824
|
+
```ts
|
|
825
|
+
const users = await hydrate(
|
|
826
|
+
db.selectFrom("users").select(["users.id", "users.name"]),
|
|
827
|
+
)
|
|
828
|
+
.map((user) => ({ ...user, nameUpper: user.name.toUpperCase() }))
|
|
829
|
+
.map((user) => ({ id: user.id, display: user.nameUpper }))
|
|
830
|
+
.execute();
|
|
831
|
+
// ⬇
|
|
832
|
+
type Result = Array<{ id: number; display: string }>;
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
#### Transforming nested collections
|
|
836
|
+
|
|
837
|
+
`.map()` works with nested collections too. You can apply transformations to
|
|
838
|
+
child entities and then to parents:
|
|
839
|
+
|
|
840
|
+
```ts
|
|
841
|
+
const users = await hydrate(db.selectFrom("users").select(["users.id"]))
|
|
842
|
+
.hasMany("posts", ({ leftJoin }) =>
|
|
843
|
+
leftJoin("posts", "posts.userId", "users.id")
|
|
844
|
+
.select(["posts.id", "posts.title"])
|
|
845
|
+
// Transform child:
|
|
846
|
+
.map((post) => ({ postId: post.id, postTitle: post.title })),
|
|
847
|
+
)
|
|
848
|
+
// Transform parent:
|
|
849
|
+
.map((user) => ({
|
|
850
|
+
userId: user.id,
|
|
851
|
+
postCount: user.posts.length,
|
|
852
|
+
posts: user.posts,
|
|
853
|
+
}))
|
|
854
|
+
.execute();
|
|
855
|
+
// ⬇
|
|
856
|
+
type Result = Array<{
|
|
857
|
+
userId: number;
|
|
858
|
+
postCount: number;
|
|
859
|
+
posts: {
|
|
860
|
+
postId: number;
|
|
861
|
+
postTitle: string;
|
|
862
|
+
};
|
|
863
|
+
}>;
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
#### Terminal operation
|
|
867
|
+
|
|
868
|
+
`.map()` is a **terminal operation**. After you call `.map()`, you can only:
|
|
869
|
+
|
|
870
|
+
- Call `.map()` again to chain another transformation
|
|
871
|
+
- Call `.modify()` to adjust the underlying SQL query
|
|
872
|
+
- Call execution methods (`.execute()`, `.executeTakeFirst()`, etc.)
|
|
873
|
+
|
|
874
|
+
You **cannot** call configuration methods like `.mapFields()`, `.extras()`,
|
|
875
|
+
`.hasMany()`, or `.with()` after `.map()`.
|
|
876
|
+
|
|
877
|
+
This is intentional: those methods would affect the *input* type expected by
|
|
878
|
+
your transformation function, which would break your mapping logic. By
|
|
879
|
+
preventing further configuration, the type system protects you from this class
|
|
880
|
+
of bugs.
|
|
881
|
+
|
|
882
|
+
```ts
|
|
883
|
+
const mapped = hydrate(db.selectFrom("users").select(["users.id"]))
|
|
884
|
+
.map((user) => ({ userId: user.id }));
|
|
885
|
+
|
|
886
|
+
// ✅ These work:
|
|
887
|
+
mapped.map((data) => ({ transformed: data.userId }));
|
|
888
|
+
mapped.execute();
|
|
889
|
+
|
|
890
|
+
// ❌ These don't compile:
|
|
891
|
+
mapped.mapFields({ ... }); // Error: Property 'mapFields' does not exist
|
|
892
|
+
mapped.hasMany(...); // Error: Property 'hasMany' does not exist
|
|
893
|
+
```
|
|
894
|
+
|
|
895
|
+
#### `.map()` vs `.mapFields()` and `.extras()`
|
|
896
|
+
|
|
897
|
+
When should you use `.map()` vs the more targeted methods?
|
|
898
|
+
|
|
899
|
+
- **Use `.mapFields()`** when you want to transform individual fields by name
|
|
900
|
+
(e.g., normalizing strings)
|
|
901
|
+
- **Use `.extras()`** when you want to add computed fields while keeping the
|
|
902
|
+
existing structure
|
|
903
|
+
- **Use `.map()`** when you need to:
|
|
904
|
+
- Convert to class instances
|
|
905
|
+
- Completely reshape the output
|
|
906
|
+
- Apply transformations that depend on the full hydrated result
|
|
907
|
+
- Assert or narrow types on the entire output shape
|
|
908
|
+
|
|
909
|
+
The targeted methods are more composable, because they can be interleaved with
|
|
910
|
+
joins, unlike `.map()`.
|
|
911
|
+
|
|
782
912
|
### Composable mappings with `.with()`
|
|
783
913
|
|
|
784
914
|
Re-use hydration logic by importing it from another `Hydrator`. This is great for
|
|
@@ -948,20 +1078,16 @@ Computes new fields from the input row.
|
|
|
948
1078
|
type UserRow = { id: number; username: string; email: string };
|
|
949
1079
|
|
|
950
1080
|
const hydrator = createHydrator<UserRow>()
|
|
951
|
-
.fields({ id: true, username: true, email: true })
|
|
952
1081
|
.extras({
|
|
953
1082
|
displayName: (u) => `${u.username} <${u.email}>`,
|
|
954
1083
|
})
|
|
955
|
-
.omit(["email"]);
|
|
956
1084
|
// ⬇
|
|
957
|
-
type Result = Array<{
|
|
1085
|
+
type Result = Array<{ displayName: string }>;
|
|
958
1086
|
```
|
|
959
1087
|
|
|
960
1088
|
### Excluding fields with `.omit()`
|
|
961
1089
|
|
|
962
|
-
Excludes fields from the output that were already included.
|
|
963
|
-
primarily exists for use by the `HydratedQueryBuilder`, which includes all
|
|
964
|
-
fields by default.
|
|
1090
|
+
Excludes fields from the output that were already included.
|
|
965
1091
|
|
|
966
1092
|
```ts
|
|
967
1093
|
type UserRow = { id: number; passwordHash: string };
|
|
@@ -973,6 +1099,53 @@ const hydrator = createHydrator<UserRow>()
|
|
|
973
1099
|
type Result = Array<{ id: number }>;
|
|
974
1100
|
```
|
|
975
1101
|
|
|
1102
|
+
This method primarily exists for use by the `HydratedQueryBuilder`, which
|
|
1103
|
+
includes all fields by default. It's not so useful in standalone Hydrators, in
|
|
1104
|
+
which you must explicitly name the fields to include. The example above is
|
|
1105
|
+
equivalent to `createHydrator<UserRow>().fields({ id: true })`.
|
|
1106
|
+
|
|
1107
|
+
### Output transformations with `.map()`
|
|
1108
|
+
|
|
1109
|
+
The `.map()` method works the same way as described in the
|
|
1110
|
+
[`hydrate()` API section](#output-transformations-with-map) above: it
|
|
1111
|
+
transforms the hydrated output into a different shape, such as class instances
|
|
1112
|
+
or discriminated union types.
|
|
1113
|
+
|
|
1114
|
+
```ts
|
|
1115
|
+
class UserModel {
|
|
1116
|
+
constructor(
|
|
1117
|
+
public id: number,
|
|
1118
|
+
public name: string,
|
|
1119
|
+
) {}
|
|
1120
|
+
}
|
|
1121
|
+
|
|
1122
|
+
const hydrator = createHydrator<{ id: number; name: string }>()
|
|
1123
|
+
.fields({ id: true, name: true })
|
|
1124
|
+
.map((user) => new UserModel(user.id, user.name));
|
|
1125
|
+
|
|
1126
|
+
const users = await hydrateData(rows, hydrator);
|
|
1127
|
+
// ⬇
|
|
1128
|
+
type Result = UserModel[];
|
|
1129
|
+
```
|
|
1130
|
+
|
|
1131
|
+
Like with `HydratedQueryBuilder`, `.map()` is a terminal operation—after
|
|
1132
|
+
calling it, you can only call `.map()` again or `.hydrate()`. You cannot call
|
|
1133
|
+
configuration methods like `.fields()`, `.extras()`, `.has*()`, or `.extend()`.
|
|
1134
|
+
|
|
1135
|
+
```ts
|
|
1136
|
+
const mapped = createHydrator<User>()
|
|
1137
|
+
.fields({ id: true })
|
|
1138
|
+
.map((u) => ({ userId: u.id }));
|
|
1139
|
+
|
|
1140
|
+
// ✅ These work:
|
|
1141
|
+
mapped.map((data) => ({ transformed: data.userId }));
|
|
1142
|
+
mapped.hydrate(rows);
|
|
1143
|
+
|
|
1144
|
+
// ❌ These don't compile:
|
|
1145
|
+
mapped.fields({ ... }); // Error: Property 'fields' does not exist
|
|
1146
|
+
mapped.extend(...); // Error: Property 'extend' does not exist
|
|
1147
|
+
```
|
|
1148
|
+
|
|
976
1149
|
### Attached collections with `.attach*()`
|
|
977
1150
|
|
|
978
1151
|
These work the same as in the `hydrate()` API (see the `.attach*()` section above).
|
|
@@ -1041,9 +1214,7 @@ type UserRow = { id: number; username: string; email: string };
|
|
|
1041
1214
|
const base = createHydrator<UserRow>().fields({ id: true, username: true });
|
|
1042
1215
|
|
|
1043
1216
|
const withDisplayName = createHydrator<UserRow>()
|
|
1044
|
-
.
|
|
1045
|
-
.extras({ displayName: (u) => `${u.username} <${u.email}>` })
|
|
1046
|
-
.omit(["email"]);
|
|
1217
|
+
.extras({ displayName: (u) => `${u.username} <${u.email}>` });
|
|
1047
1218
|
|
|
1048
1219
|
const combined = base.extend(withDisplayName);
|
|
1049
1220
|
// ⬇
|
package/dist/index.d.mts
CHANGED
|
@@ -80,24 +80,6 @@ type InferExtras<Input, E extends Extras<Input>> = { [K in keyof E]: ReturnType<
|
|
|
80
80
|
* is thrown if the object is null when hydrating.
|
|
81
81
|
*/
|
|
82
82
|
type CollectionMode = "many" | "one" | "oneOrThrow";
|
|
83
|
-
/**
|
|
84
|
-
* Configuration for a nested collection.
|
|
85
|
-
*/
|
|
86
|
-
interface Collection<ChildInput, ChildOutput> {
|
|
87
|
-
/**
|
|
88
|
-
* The mode of the nested entity: "one" (or "oneOrThrow") for a single
|
|
89
|
-
* object, "many" for an array.
|
|
90
|
-
*/
|
|
91
|
-
readonly mode: CollectionMode;
|
|
92
|
-
/**
|
|
93
|
-
* The prefix to use for the nested collection.
|
|
94
|
-
*/
|
|
95
|
-
readonly prefix: string;
|
|
96
|
-
/**
|
|
97
|
-
* The Hydrator to use when hydrating the objects in the nested collection.
|
|
98
|
-
*/
|
|
99
|
-
readonly hydrator: Hydrator<ChildInput, ChildOutput>;
|
|
100
|
-
}
|
|
101
83
|
/**
|
|
102
84
|
* Async function that fetches and hydrates data to attach. Called exactly once with
|
|
103
85
|
* all parent inputs to avoid N+1 queries. Should return already-hydrated data.
|
|
@@ -117,81 +99,15 @@ interface AttachedKeysArg<ParentInput, AttachedOutput> {
|
|
|
117
99
|
*/
|
|
118
100
|
readonly toParent?: KeyBy<ParentInput> | undefined;
|
|
119
101
|
}
|
|
120
|
-
/**
|
|
121
|
-
* Configuration for an attached collection.
|
|
122
|
-
*/
|
|
123
|
-
interface AttachedCollection<ParentInput, AttachedOutput> {
|
|
124
|
-
/**
|
|
125
|
-
* The mode of the attached collection: "one" (or "oneOrThrow") for a single
|
|
126
|
-
* object, "many" for an array.
|
|
127
|
-
*/
|
|
128
|
-
readonly mode: CollectionMode;
|
|
129
|
-
/**
|
|
130
|
-
* Async function that fetches and hydrates the data to attach. Called exactly once with
|
|
131
|
-
* all parent inputs to avoid N+1 queries. Should return already-hydrated data.
|
|
132
|
-
*/
|
|
133
|
-
readonly fetchFn: FetchFn<ParentInput, AttachedOutput>;
|
|
134
|
-
/**
|
|
135
|
-
* The key(s) on the attached child output to use for matching to parents.
|
|
136
|
-
*/
|
|
137
|
-
readonly matchChild: KeyBy<AttachedOutput>;
|
|
138
|
-
/**
|
|
139
|
-
* The key(s) on the parent input to compare with the attached child output's key.
|
|
140
|
-
*/
|
|
141
|
-
readonly toParent: KeyBy<ParentInput>;
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Internal map type for fields configuration.
|
|
145
|
-
*/
|
|
146
|
-
type FieldsMap = Map<string, true | false | ((value: any) => unknown)>;
|
|
147
|
-
/**
|
|
148
|
-
* Internal map type for extras configuration.
|
|
149
|
-
*/
|
|
150
|
-
type ExtrasMap = Map<string, (input: any) => unknown>;
|
|
151
|
-
/**
|
|
152
|
-
* Internal map type for nested collections configuration.
|
|
153
|
-
*/
|
|
154
|
-
type CollectionsMap = Map<string, Collection<any, any>>;
|
|
155
|
-
/**
|
|
156
|
-
* Internal map type for attached collections configuration.
|
|
157
|
-
*/
|
|
158
|
-
type AttachedCollectionsMap = Map<string, AttachedCollection<any, any>>;
|
|
159
|
-
/**
|
|
160
|
-
* Internal configuration for a Hydrator.
|
|
161
|
-
*/
|
|
162
|
-
interface HydratorProps<Input> {
|
|
163
|
-
/**
|
|
164
|
-
* The key(s) to group by for this entity.
|
|
165
|
-
* Can be a single key or an array of keys for composite keys.
|
|
166
|
-
*/
|
|
167
|
-
readonly keyBy: KeyBy<Input>;
|
|
168
|
-
/**
|
|
169
|
-
* The fields to include in the final denormalized entity. You can either specify `true` to
|
|
170
|
-
* include a field as-is, or provide a transformation function to modify the field's value.
|
|
171
|
-
*/
|
|
172
|
-
readonly fields?: FieldsMap | undefined;
|
|
173
|
-
/**
|
|
174
|
-
* Extra fields generated from the entire input.
|
|
175
|
-
*/
|
|
176
|
-
readonly extras?: ExtrasMap | undefined;
|
|
177
|
-
/**
|
|
178
|
-
* An optional map of nested collections.
|
|
179
|
-
*/
|
|
180
|
-
readonly collections?: CollectionsMap | undefined;
|
|
181
|
-
/**
|
|
182
|
-
* An optional map of attached collections (for application-level joins).
|
|
183
|
-
*/
|
|
184
|
-
readonly attachedCollections?: AttachedCollectionsMap | undefined;
|
|
185
|
-
}
|
|
186
102
|
/**
|
|
187
103
|
* Type for createHydrator when Input extends InputWithDefaultKey or not.
|
|
188
104
|
* Allows optional keyBy only if Input extends InputWithDefaultKey.
|
|
189
105
|
*/
|
|
190
106
|
interface CreateHydratorWithoutDefaultKey<Input> {
|
|
191
|
-
(keyBy: KeyBy<Input>):
|
|
107
|
+
(keyBy: KeyBy<Input>): FullHydrator<Input, {}>;
|
|
192
108
|
}
|
|
193
109
|
interface CreateHydratorWithDefaultKey<Input> extends CreateHydratorWithoutDefaultKey<Input> {
|
|
194
|
-
():
|
|
110
|
+
(): FullHydrator<Input, {}>;
|
|
195
111
|
}
|
|
196
112
|
/**
|
|
197
113
|
* Type for a createHydrator function scoped to a specific Input type.
|
|
@@ -200,17 +116,17 @@ type CreateHydratorFn<Input> = Input extends InputWithDefaultKey ? CreateHydrato
|
|
|
200
116
|
/**
|
|
201
117
|
* A function that creates a Hydrator.
|
|
202
118
|
*/
|
|
203
|
-
type HydratorFactory<Input, Output> = (create: CreateHydratorFn<Input>) =>
|
|
119
|
+
type HydratorFactory<Input, Output> = (create: CreateHydratorFn<Input>) => MappedHydrator<Input, Output>;
|
|
204
120
|
/**
|
|
205
121
|
* A Hydrator instance or a function that creates one.
|
|
206
122
|
* Used to allow inline Hydrator creation in method calls.
|
|
207
123
|
*/
|
|
208
|
-
type HydratorArg<Input, Output> =
|
|
124
|
+
type HydratorArg<Input, Output> = MappedHydrator<Input, Output> | HydratorFactory<Input, Output>;
|
|
209
125
|
/**
|
|
210
126
|
* A Hydrator instance for a child collection or a function that creates one.
|
|
211
127
|
* The input type is automatically prefixed based on the parent's prefix.
|
|
212
128
|
*/
|
|
213
|
-
type ChildHydratorArg<P extends string, ParentInput, ChildOutput> =
|
|
129
|
+
type ChildHydratorArg<P extends string, ParentInput, ChildOutput> = MappedHydrator<SelectAndStripPrefix<P, ParentInput>, ChildOutput> | ((create: CreateHydratorFn<SelectAndStripPrefix<P, ParentInput>>) => MappedHydrator<SelectAndStripPrefix<P, ParentInput>, ChildOutput>);
|
|
214
130
|
/**
|
|
215
131
|
* Ensures fields are included in the Hydrator's output if they don't already
|
|
216
132
|
* have an explicit configuration (including explicit omission).
|
|
@@ -225,6 +141,7 @@ type ChildHydratorArg<P extends string, ParentInput, ChildOutput> = Hydrator<Sel
|
|
|
225
141
|
* @internal
|
|
226
142
|
*/
|
|
227
143
|
|
|
144
|
+
declare const IsFullHydrator: unique symbol;
|
|
228
145
|
/**
|
|
229
146
|
* A configuration for how to hydrate flat database rows into a denormalized structure.
|
|
230
147
|
*
|
|
@@ -233,15 +150,64 @@ type ChildHydratorArg<P extends string, ParentInput, ChildOutput> = Hydrator<Sel
|
|
|
233
150
|
* - Extra computed fields
|
|
234
151
|
* - Nested collections (using `has()` methods)
|
|
235
152
|
* - Attached collections (using `attach()` methods)
|
|
153
|
+
* - Map functions to apply to the hydrated output
|
|
236
154
|
*
|
|
237
155
|
* Once configured, call `hydrate()` to transform input data into the denormalized output.
|
|
238
156
|
*
|
|
239
157
|
* @template Input - The type of the input data (typically from a database query)
|
|
240
158
|
* @template Output - The type of the hydrated output structure
|
|
241
159
|
*/
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
160
|
+
type Hydrator<Input, Output> = MappedHydrator<Input, Output> | FullHydrator<Input, Output>;
|
|
161
|
+
/**
|
|
162
|
+
* Determines if a hydrator is a full hydrator, meaning it has not had a .map()
|
|
163
|
+
* applied to it yet.
|
|
164
|
+
*
|
|
165
|
+
* @param hydrator - The hydrator to check
|
|
166
|
+
* @returns True if the hydrator is a full hydrator, false otherwise
|
|
167
|
+
*/
|
|
168
|
+
declare const isFullHydrator: <Input, Output>(hydrator: Hydrator<Input, Output>) => hydrator is FullHydrator<Input, Output>;
|
|
169
|
+
/**
|
|
170
|
+
* Base interface for a mapped hydrator that only allows hydration and further mapping.
|
|
171
|
+
* This is returned after calling `.map()` to prevent further configuration.
|
|
172
|
+
*/
|
|
173
|
+
interface MappedHydrator<Input, Output> {
|
|
174
|
+
[IsFullHydrator]: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Applies a transformation function to the hydrated output.
|
|
177
|
+
*
|
|
178
|
+
* This is a terminal operation: after calling `.map()`, only `.map()` and
|
|
179
|
+
* `.hydrate()` are available.
|
|
180
|
+
*
|
|
181
|
+
* Use this for more complex transformations, such as:
|
|
182
|
+
* - Hydrating into class instances
|
|
183
|
+
* - Asserting discriminated union types
|
|
184
|
+
* - Complex data reshaping
|
|
185
|
+
*
|
|
186
|
+
* For simple field transformations, prefer `.fields()` or `.extras()`.
|
|
187
|
+
*
|
|
188
|
+
* @param fn - A function that transforms the hydrated output
|
|
189
|
+
* @returns A MappedHydrator with the transformation added
|
|
190
|
+
*/
|
|
191
|
+
map<NewOutput>(fn: (output: Output) => NewOutput): MappedHydrator<Input, NewOutput>;
|
|
192
|
+
/**
|
|
193
|
+
* Hydrates the input data into a denormalized structure according to this configuration.
|
|
194
|
+
*
|
|
195
|
+
* If attached collections are configured, this method will fetch them asynchronously
|
|
196
|
+
* before performing the hydration. The method always returns a Promise for consistency.
|
|
197
|
+
*
|
|
198
|
+
* @param input - A single input entity or an iterable of input entities
|
|
199
|
+
* @returns A Promise that resolves to the hydrated output(s)
|
|
200
|
+
*/
|
|
201
|
+
hydrate(input: Iterable<Input>): Promise<Output[]>;
|
|
202
|
+
hydrate(input: Input | Iterable<Input>): Promise<Output | Output[]>;
|
|
203
|
+
hydrate(input: Input): Promise<Output>;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Full hydrator interface with all configuration methods.
|
|
207
|
+
* Extends MappedHydrator but `.map()` returns MappedHydrator to make it terminal.
|
|
208
|
+
*/
|
|
209
|
+
interface FullHydrator<Input, Output> extends MappedHydrator<Input, Output> {
|
|
210
|
+
[IsFullHydrator]: true;
|
|
245
211
|
/**
|
|
246
212
|
* Configures which fields to include in the hydrated output.
|
|
247
213
|
*
|
|
@@ -249,14 +215,14 @@ declare class Hydrator<Input, Output> {
|
|
|
249
215
|
* or a transformation function
|
|
250
216
|
* @returns A new Hydrator with the fields configuration merged
|
|
251
217
|
*/
|
|
252
|
-
fields<F extends Fields<Input>>(fields: F):
|
|
218
|
+
fields<F extends Fields<Input>>(fields: F): FullHydrator<Input, Extend<Output, InferFields<Input, F>>>;
|
|
253
219
|
/**
|
|
254
220
|
* Omits specified fields from the hydrated output.
|
|
255
221
|
*
|
|
256
222
|
* @param keys - Field names to omit from the output
|
|
257
223
|
* @returns A new Hydrator with the fields omitted
|
|
258
224
|
*/
|
|
259
|
-
omit<K$1 extends keyof Input>(keys: readonly K$1[]):
|
|
225
|
+
omit<K$1 extends keyof Input>(keys: readonly K$1[]): FullHydrator<Input, Omit<Output, K$1>>;
|
|
260
226
|
/**
|
|
261
227
|
* Configures extra computed fields to add to the hydrated output.
|
|
262
228
|
*
|
|
@@ -264,7 +230,7 @@ declare class Hydrator<Input, Output> {
|
|
|
264
230
|
* the field value from the entire input
|
|
265
231
|
* @returns A new Hydrator with the extras configuration merged
|
|
266
232
|
*/
|
|
267
|
-
extras<E extends Extras<Input>>(extras: E):
|
|
233
|
+
extras<E extends Extras<Input>>(extras: E): FullHydrator<Input, Extend<Output, InferExtras<Input, E>>>;
|
|
268
234
|
/**
|
|
269
235
|
* Extends this Hydrator with the configuration from another Hydrator. The
|
|
270
236
|
* other Hydrator's configuration takes precedence in case of conflicts.
|
|
@@ -276,7 +242,8 @@ declare class Hydrator<Input, Output> {
|
|
|
276
242
|
* @returns A new Hydrator with merged configuration
|
|
277
243
|
* @throws {KeyByMismatchError} If the keyBy configurations don't match
|
|
278
244
|
*/
|
|
279
|
-
extend<OtherInput extends Partial<Input>, OtherOutput>(other:
|
|
245
|
+
extend<OtherInput extends Partial<Input>, OtherOutput>(other: FullHydrator<OtherInput, OtherOutput>): FullHydrator<Input & OtherInput, Extend<Output, OtherOutput>>;
|
|
246
|
+
extend<OtherInput extends Partial<Input>, OtherOutput>(other: MappedHydrator<OtherInput, OtherOutput>): MappedHydrator<Input & OtherInput, Extend<Output, OtherOutput>>;
|
|
280
247
|
/**
|
|
281
248
|
* Configures a nested collection that exists in the same query result. The
|
|
282
249
|
* child data is expected to be prefixed in the input (e.g., `posts$$id`,
|
|
@@ -293,10 +260,10 @@ declare class Hydrator<Input, Output> {
|
|
|
293
260
|
* a function that creates one.
|
|
294
261
|
* @returns A new Hydrator with the nested collection added.
|
|
295
262
|
*/
|
|
296
|
-
has<K$1 extends string, P extends string, ChildOutput>(mode: "many", key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>):
|
|
297
|
-
has<K$1 extends string, P extends string, ChildOutput>(mode: "one", key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>):
|
|
298
|
-
has<K$1 extends string, P extends string, ChildOutput>(mode: "oneOrThrow", key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>):
|
|
299
|
-
has<K$1 extends string, P extends string, ChildOutput>(mode: CollectionMode, key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>):
|
|
263
|
+
has<K$1 extends string, P extends string, ChildOutput>(mode: "many", key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput[] }>>;
|
|
264
|
+
has<K$1 extends string, P extends string, ChildOutput>(mode: "one", key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput | null }>>;
|
|
265
|
+
has<K$1 extends string, P extends string, ChildOutput>(mode: "oneOrThrow", key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput }>>;
|
|
266
|
+
has<K$1 extends string, P extends string, ChildOutput>(mode: CollectionMode, key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput[] | ChildOutput | null }>>;
|
|
300
267
|
/**
|
|
301
268
|
* Shorthand for `has("many", ...)` - configures a nested array collection.
|
|
302
269
|
*
|
|
@@ -305,7 +272,7 @@ declare class Hydrator<Input, Output> {
|
|
|
305
272
|
* @param hydrator - The Hydrator configuration for the child entities
|
|
306
273
|
* @returns A new Hydrator with the nested collection added
|
|
307
274
|
*/
|
|
308
|
-
hasMany<K$1 extends string, P extends string, ChildOutput>(key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>):
|
|
275
|
+
hasMany<K$1 extends string, P extends string, ChildOutput>(key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput[] }>>;
|
|
309
276
|
/**
|
|
310
277
|
* Shorthand for `has("one", ...)` - configures a nested nullable single entity.
|
|
311
278
|
*
|
|
@@ -314,7 +281,7 @@ declare class Hydrator<Input, Output> {
|
|
|
314
281
|
* @param hydrator - The Hydrator configuration for the child entity
|
|
315
282
|
* @returns A new Hydrator with the nested entity added
|
|
316
283
|
*/
|
|
317
|
-
hasOne<K$1 extends string, P extends string, ChildOutput>(key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>):
|
|
284
|
+
hasOne<K$1 extends string, P extends string, ChildOutput>(key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput | null }>>;
|
|
318
285
|
/**
|
|
319
286
|
* Shorthand for `has("oneOrThrow", ...)` - configures a nested non-nullable single entity.
|
|
320
287
|
* Throws an error if the entity is not found during hydration.
|
|
@@ -324,7 +291,7 @@ declare class Hydrator<Input, Output> {
|
|
|
324
291
|
* @param hydrator - The Hydrator configuration for the child entity.
|
|
325
292
|
* @returns A new Hydrator with the nested entity added.
|
|
326
293
|
*/
|
|
327
|
-
hasOneOrThrow<K$1 extends string, P extends string, ChildOutput>(key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>):
|
|
294
|
+
hasOneOrThrow<K$1 extends string, P extends string, ChildOutput>(key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput }>>;
|
|
328
295
|
/**
|
|
329
296
|
* Configures an attached collection that is fetched from an external source.
|
|
330
297
|
* The `fetchFn` is called exactly once per hydration with all parent inputs
|
|
@@ -344,10 +311,10 @@ declare class Hydrator<Input, Output> {
|
|
|
344
311
|
* attached child's key.
|
|
345
312
|
* @returns A new Hydrator with the attached collection added.
|
|
346
313
|
*/
|
|
347
|
-
attach<K$1 extends string, AttachedOutput>(mode: "many", key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>):
|
|
348
|
-
attach<K$1 extends string, AttachedOutput>(mode: "one", key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>):
|
|
349
|
-
attach<K$1 extends string, AttachedOutput>(mode: "oneOrThrow", key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>):
|
|
350
|
-
attach<K$1 extends string, AttachedOutput>(mode: CollectionMode, key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>):
|
|
314
|
+
attach<K$1 extends string, AttachedOutput>(mode: "many", key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput[] }>>;
|
|
315
|
+
attach<K$1 extends string, AttachedOutput>(mode: "one", key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput | null }>>;
|
|
316
|
+
attach<K$1 extends string, AttachedOutput>(mode: "oneOrThrow", key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput }>>;
|
|
317
|
+
attach<K$1 extends string, AttachedOutput>(mode: CollectionMode, key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput[] | AttachedOutput | null }>>;
|
|
351
318
|
/**
|
|
352
319
|
* Shorthand for `attach("many", ...)` - configures an attached array collection.
|
|
353
320
|
*
|
|
@@ -357,7 +324,7 @@ declare class Hydrator<Input, Output> {
|
|
|
357
324
|
* @param keys.toParent - The key(s) on the parent input to compare with the child's key.
|
|
358
325
|
* @returns A new Hydrator with the attached collection added.
|
|
359
326
|
*/
|
|
360
|
-
attachMany<K$1 extends string, AttachedOutput>(key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>):
|
|
327
|
+
attachMany<K$1 extends string, AttachedOutput>(key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput[] }>>;
|
|
361
328
|
/**
|
|
362
329
|
* Shorthand for `attach("one", ...)` - configures an attached nullable single entity.
|
|
363
330
|
*
|
|
@@ -367,7 +334,7 @@ declare class Hydrator<Input, Output> {
|
|
|
367
334
|
* @param keys.toParent - The key(s) on the parent input to compare with the child's key.
|
|
368
335
|
* @returns A new Hydrator with the attached entity added.
|
|
369
336
|
*/
|
|
370
|
-
attachOne<K$1 extends string, AttachedOutput>(key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>):
|
|
337
|
+
attachOne<K$1 extends string, AttachedOutput>(key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput | null }>>;
|
|
371
338
|
/**
|
|
372
339
|
* Shorthand for `attach("oneOrThrow", ...)` - configures an attached non-nullable single entity.
|
|
373
340
|
* Throws an error if the entity is not found during hydration.
|
|
@@ -378,19 +345,7 @@ declare class Hydrator<Input, Output> {
|
|
|
378
345
|
* @param keys.toParent - The key(s) on the parent input to compare with the child's key.
|
|
379
346
|
* @returns A new Hydrator with the attached entity added
|
|
380
347
|
*/
|
|
381
|
-
attachOneOrThrow<K$1 extends string, AttachedOutput>(key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>):
|
|
382
|
-
/**
|
|
383
|
-
* Hydrates the input data into a denormalized structure according to this configuration.
|
|
384
|
-
*
|
|
385
|
-
* If attached collections are configured, this method will fetch them asynchronously
|
|
386
|
-
* before performing the hydration. The method always returns a Promise for consistency.
|
|
387
|
-
*
|
|
388
|
-
* @param input - A single input entity or an iterable of input entities
|
|
389
|
-
* @returns A Promise that resolves to the hydrated output(s)
|
|
390
|
-
*/
|
|
391
|
-
hydrate(input: Iterable<Input>): Promise<Output[]>;
|
|
392
|
-
hydrate(input: Input | Iterable<Input>): Promise<Output | Output[]>;
|
|
393
|
-
hydrate(input: Input): Promise<Output>;
|
|
348
|
+
attachOneOrThrow<K$1 extends string, AttachedOutput>(key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): FullHydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput }>>;
|
|
394
349
|
}
|
|
395
350
|
/**
|
|
396
351
|
* Creates a new Hydrator---a configuration for how to hydrate an entity into
|
|
@@ -399,8 +354,8 @@ declare class Hydrator<Input, Output> {
|
|
|
399
354
|
* @param keyBy - The key(s) to group by for this entity.
|
|
400
355
|
* Defaults to "id" if the input type has an "id" property.
|
|
401
356
|
*/
|
|
402
|
-
declare function createHydrator<T>(keyBy: KeyBy<NoInfer<T>>):
|
|
403
|
-
declare function createHydrator<T extends InputWithDefaultKey>():
|
|
357
|
+
declare function createHydrator<T>(keyBy: KeyBy<NoInfer<T>>): FullHydrator<T, {}>;
|
|
358
|
+
declare function createHydrator<T extends InputWithDefaultKey>(): FullHydrator<T, {}>;
|
|
404
359
|
/**
|
|
405
360
|
* Hydrates an entity or collection of entities into a denormalized structure
|
|
406
361
|
* per the given Hydrator configuration.
|
|
@@ -414,6 +369,85 @@ declare function hydrateData<Input, Output>(input: Input | readonly Input[], hyd
|
|
|
414
369
|
declare function hydrateData<Input, Output>(input: Input, hydrator: HydratorArg<NoInfer<Input>, Output>): Promise<Output>;
|
|
415
370
|
//#endregion
|
|
416
371
|
//#region src/query-builder.d.ts
|
|
372
|
+
/**
|
|
373
|
+
* Super type to HydratedQueryBuilder, that has already had a .map() added,
|
|
374
|
+
* meaning it's no longer safe to continue to chain methods like .mapFields() or
|
|
375
|
+
* .hasMany(), because those will affect the input type expected by the
|
|
376
|
+
* transformation function applied to .map().
|
|
377
|
+
*
|
|
378
|
+
* The generic parameters are the same as HydratedQueryBuilder.
|
|
379
|
+
*/
|
|
380
|
+
interface MappedHydratedQueryBuilder<Prefix extends string, QueryDB, QueryTB extends keyof QueryDB, QueryRow, LocalDB, LocalRow, HydratedRow, IsNullable extends boolean, HasJoin extends boolean> {
|
|
381
|
+
/**
|
|
382
|
+
* This property exists for complex type reasons and will never be set.
|
|
383
|
+
*
|
|
384
|
+
* @internal
|
|
385
|
+
*/
|
|
386
|
+
readonly _generics: {
|
|
387
|
+
Prefix: Prefix;
|
|
388
|
+
QueryDB: QueryDB;
|
|
389
|
+
QueryTB: QueryTB;
|
|
390
|
+
QueryRow: QueryRow;
|
|
391
|
+
LocalRow: LocalRow;
|
|
392
|
+
HydratedRow: HydratedRow;
|
|
393
|
+
IsNullable: IsNullable;
|
|
394
|
+
NestedDB: LocalDB;
|
|
395
|
+
HasJoin: HasJoin;
|
|
396
|
+
} | undefined;
|
|
397
|
+
/**
|
|
398
|
+
* Allows you to modify the underlying select query. Useful for adding
|
|
399
|
+
* `where` clauses. Adding additional SELECTs here is forbidden.
|
|
400
|
+
*
|
|
401
|
+
* For example:
|
|
402
|
+
*
|
|
403
|
+
* ```ts
|
|
404
|
+
* hydrate(...).modify((qb) => qb.where("isActive", "=", "true"))
|
|
405
|
+
* ```
|
|
406
|
+
*/
|
|
407
|
+
modify(modifier: (qb: k$1.SelectQueryBuilder<QueryDB, QueryTB, QueryRow>) => k$1.SelectQueryBuilder<QueryDB, QueryTB, QueryRow>): MappedHydratedQueryBuilder<Prefix, QueryDB, QueryTB, QueryRow, LocalDB, LocalRow, HydratedRow, IsNullable, HasJoin>;
|
|
408
|
+
/**
|
|
409
|
+
* Returns the raw underlying Kysely select query builder.
|
|
410
|
+
* Useful for debugging or when you need direct access to the query.
|
|
411
|
+
*/
|
|
412
|
+
toQuery(): k$1.SelectQueryBuilder<QueryDB, QueryTB, QueryRow>;
|
|
413
|
+
/**
|
|
414
|
+
* Executes the query and returns an array of rows.
|
|
415
|
+
*
|
|
416
|
+
* Also see the {@link executeTakeFirst} and {@link executeTakeFirstOrThrow} methods.
|
|
417
|
+
*/
|
|
418
|
+
execute(): Promise<k$1.Simplify<HydratedRow>[]>;
|
|
419
|
+
/**
|
|
420
|
+
* Executes the query and returns the first result or undefined if the query
|
|
421
|
+
* returned no result.
|
|
422
|
+
*/
|
|
423
|
+
executeTakeFirst(): Promise<k$1.Simplify<HydratedRow> | undefined>;
|
|
424
|
+
/**
|
|
425
|
+
* Executes the query and returns the first result or throws if the query
|
|
426
|
+
* returned no result.
|
|
427
|
+
*
|
|
428
|
+
* By default an instance of {@link k.NoResultError} is thrown, but you can
|
|
429
|
+
* provide a custom error class, or callback to throw a different error.
|
|
430
|
+
*/
|
|
431
|
+
executeTakeFirstOrThrow(errorConstructor?: k$1.NoResultErrorConstructor | ((node: k$1.QueryNode) => Error)): Promise<k$1.Simplify<HydratedRow>>;
|
|
432
|
+
/**
|
|
433
|
+
* Applies a transformation function to the hydrated output.
|
|
434
|
+
*
|
|
435
|
+
* This is a terminal operation: after calling `.map()`, only `.map()` and
|
|
436
|
+
* `.execute()` are available; you cannot continue to chain methods that
|
|
437
|
+
* affect the input type expected by the transformation function.
|
|
438
|
+
*
|
|
439
|
+
* Use this for more complex transformations, such as:
|
|
440
|
+
* - Hydrating into class instances
|
|
441
|
+
* - Asserting discriminated union types
|
|
442
|
+
* - Complex data reshaping
|
|
443
|
+
*
|
|
444
|
+
* For simple field transformations, prefer `.fields()` or `.extras()`.
|
|
445
|
+
*
|
|
446
|
+
* @param transform - A function that transforms the hydrated output
|
|
447
|
+
* @returns A MappedHydratedQueryBuilder with the transformation added
|
|
448
|
+
*/
|
|
449
|
+
map<NewHydratedRow>(transform: (row: k$1.Simplify<HydratedRow>) => NewHydratedRow): MappedHydratedQueryBuilder<Prefix, QueryDB, QueryTB, QueryRow, LocalDB, LocalRow, NewHydratedRow, IsNullable, HasJoin>;
|
|
450
|
+
}
|
|
417
451
|
/**
|
|
418
452
|
* A query builder that supports both mapping and nested joins.
|
|
419
453
|
*
|
|
@@ -437,33 +471,8 @@ declare function hydrateData<Input, Output>(input: Input, hydrator: HydratorArg<
|
|
|
437
471
|
* @template HasJoin Preserves whether this join builder has already had a join
|
|
438
472
|
* added, which affects the nullability of this relation when adding more joins.
|
|
439
473
|
*/
|
|
440
|
-
interface HydratedQueryBuilder<Prefix extends string, QueryDB, QueryTB extends keyof QueryDB, QueryRow, LocalDB, LocalRow, HydratedRow, IsNullable extends boolean, HasJoin extends boolean> {
|
|
441
|
-
|
|
442
|
-
* @internal This is is a fake method that does nothing and is only for
|
|
443
|
-
* testing types. The callback will never actually be called.
|
|
444
|
-
*/
|
|
445
|
-
_generics(cb: (args: {
|
|
446
|
-
Prefix: Prefix;
|
|
447
|
-
QueryDB: QueryDB;
|
|
448
|
-
QueryTB: QueryTB;
|
|
449
|
-
QueryRow: QueryRow;
|
|
450
|
-
LocalRow: LocalRow;
|
|
451
|
-
HydratedRow: HydratedRow;
|
|
452
|
-
IsNullable: IsNullable;
|
|
453
|
-
NestedDB: LocalDB;
|
|
454
|
-
HasJoin: HasJoin;
|
|
455
|
-
}) => void): this;
|
|
456
|
-
/**
|
|
457
|
-
* Allows you to modify the underlying select query. Useful for adding
|
|
458
|
-
* `where` clauses. Adding additional SELECTs here is discouraged.
|
|
459
|
-
*
|
|
460
|
-
* ### Examples
|
|
461
|
-
*
|
|
462
|
-
* ```ts
|
|
463
|
-
* nestableQuery.modify((qb) => qb.where("isActive", "=", "true"))
|
|
464
|
-
* ```
|
|
465
|
-
*/
|
|
466
|
-
modify<NewQueryDB, NewQueryTB extends keyof NewQueryDB, NewQueryRow extends QueryRow>(modifier: (qb: k$1.SelectQueryBuilder<QueryDB, QueryTB, QueryRow>) => k$1.SelectQueryBuilder<NewQueryDB, NewQueryTB, NewQueryRow>): HydratedQueryBuilder<Prefix, NewQueryDB, NewQueryTB, NewQueryRow, LocalDB, LocalRow, Extend<NewQueryRow, HydratedRow>, IsNullable, HasJoin>;
|
|
474
|
+
interface HydratedQueryBuilder<Prefix extends string, QueryDB, QueryTB extends keyof QueryDB, QueryRow, LocalDB, LocalRow, HydratedRow, IsNullable extends boolean, HasJoin extends boolean> extends MappedHydratedQueryBuilder<Prefix, QueryDB, QueryTB, QueryRow, LocalDB, LocalRow, HydratedRow, IsNullable, HasJoin> {
|
|
475
|
+
modify(modifier: (qb: k$1.SelectQueryBuilder<QueryDB, QueryTB, QueryRow>) => k$1.SelectQueryBuilder<QueryDB, QueryTB, QueryRow>): HydratedQueryBuilder<Prefix, QueryDB, QueryTB, QueryRow, LocalDB, LocalRow, HydratedRow, IsNullable, HasJoin>;
|
|
467
476
|
/**
|
|
468
477
|
* Configures extra computed fields to add to the hydrated output.
|
|
469
478
|
* Each extra is a function that receives the full row (with prefixed columns
|
|
@@ -561,31 +570,8 @@ interface HydratedQueryBuilder<Prefix extends string, QueryDB, QueryTB extends k
|
|
|
561
570
|
* @param hydrator - The Hydrator to extend with.
|
|
562
571
|
* @returns A new HydratedQueryBuilder with merged hydration configuration.
|
|
563
572
|
*/
|
|
564
|
-
with<OtherInput extends StrictSubset<LocalRow, OtherInput>, OtherOutput>(hydrator:
|
|
565
|
-
|
|
566
|
-
* Returns the raw underlying Kysely select query builder.
|
|
567
|
-
* Useful for debugging or when you need direct access to the query.
|
|
568
|
-
*/
|
|
569
|
-
toQuery(): k$1.SelectQueryBuilder<QueryDB, QueryTB, QueryRow>;
|
|
570
|
-
/**
|
|
571
|
-
* Executes the query and returns an array of rows.
|
|
572
|
-
*
|
|
573
|
-
* Also see the {@link executeTakeFirst} and {@link executeTakeFirstOrThrow} methods.
|
|
574
|
-
*/
|
|
575
|
-
execute(): Promise<k$1.Simplify<HydratedRow>[]>;
|
|
576
|
-
/**
|
|
577
|
-
* Executes the query and returns the first result or undefined if the query
|
|
578
|
-
* returned no result.
|
|
579
|
-
*/
|
|
580
|
-
executeTakeFirst(): Promise<k$1.Simplify<HydratedRow> | undefined>;
|
|
581
|
-
/**
|
|
582
|
-
* Executes the query and returns the first result or throws if the query
|
|
583
|
-
* returned no result.
|
|
584
|
-
*
|
|
585
|
-
* By default an instance of {@link k.NoResultError} is thrown, but you can
|
|
586
|
-
* provide a custom error class, or callback to throw a different error.
|
|
587
|
-
*/
|
|
588
|
-
executeTakeFirstOrThrow(errorConstructor?: k$1.NoResultErrorConstructor | ((node: k$1.QueryNode) => Error)): Promise<k$1.Simplify<HydratedRow>>;
|
|
573
|
+
with<OtherInput extends StrictSubset<LocalRow, OtherInput>, OtherOutput>(hydrator: FullHydrator<OtherInput, OtherOutput>): HydratedQueryBuilder<Prefix, QueryDB, QueryTB, QueryRow, LocalDB, LocalRow, Extend<HydratedRow, OtherOutput>, IsNullable, HasJoin>;
|
|
574
|
+
with<OtherInput extends StrictSubset<LocalRow, OtherInput>, OtherOutput>(hydrator: MappedHydrator<OtherInput, OtherOutput>): MappedHydratedQueryBuilder<Prefix, QueryDB, QueryTB, QueryRow, LocalDB, LocalRow, Extend<HydratedRow, OtherOutput>, IsNullable, HasJoin>;
|
|
589
575
|
/**
|
|
590
576
|
* Adds a join to the query that will hydrate into a nested collection.
|
|
591
577
|
*
|
|
@@ -624,12 +610,12 @@ interface HydratedQueryBuilder<Prefix extends string, QueryDB, QueryTB extends k
|
|
|
624
610
|
// LocalRow is empty within the nesting.
|
|
625
611
|
{},
|
|
626
612
|
// HydratedRow is empty within the nesting.
|
|
627
|
-
false, false>) =>
|
|
613
|
+
false, false>) => MappedHydratedQueryBuilder<MakePrefix<Prefix, NoInfer<K$1>>, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, NestedLocalRow, NestedHydratedRow, any, any>, keyBy: KeyBy<NestedLocalRow>): HydratedQueryBuilder<Prefix, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, LocalRow & ApplyPrefixes<MakePrefix<"", K$1>, NestedLocalRow>, Extend<HydratedRow, { [_ in K$1]: NestedHydratedRow[] }>, IsNullable, HasJoin>;
|
|
628
614
|
hasMany<K$1 extends string, JoinedQueryDB, JoinedQueryTB extends keyof JoinedQueryDB, JoinedQueryRow, NestedLocalDB, NestedLocalRow extends InputWithDefaultKey, NestedHydratedRow>(key: K$1, jb: (nb: HydratedQueryBuilder<MakePrefix<Prefix, NoInfer<K$1>>, QueryDB, QueryTB, QueryRow, LocalDB, {},
|
|
629
615
|
// LocalRow is empty within the nesting.
|
|
630
616
|
{},
|
|
631
617
|
// HydratedRow is empty within the nesting.
|
|
632
|
-
false, false>) =>
|
|
618
|
+
false, false>) => MappedHydratedQueryBuilder<MakePrefix<Prefix, NoInfer<K$1>>, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, NestedLocalRow, NestedHydratedRow, any, any>): HydratedQueryBuilder<Prefix, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, LocalRow & ApplyPrefixes<MakePrefix<"", K$1>, NestedLocalRow>, Extend<HydratedRow, { [_ in K$1]: NestedHydratedRow[] }>, IsNullable, HasJoin>;
|
|
633
619
|
/**
|
|
634
620
|
* Adds a join to the query that will hydrate into a single nested object.
|
|
635
621
|
* The object will be nullable if you use a left join, and non-nullable if you
|
|
@@ -670,12 +656,12 @@ interface HydratedQueryBuilder<Prefix extends string, QueryDB, QueryTB extends k
|
|
|
670
656
|
// LocalRow is empty within the nesting.
|
|
671
657
|
{},
|
|
672
658
|
// HydratedRow is empty within the nesting.
|
|
673
|
-
false, false>) =>
|
|
659
|
+
false, false>) => MappedHydratedQueryBuilder<MakePrefix<Prefix, NoInfer<K$1>>, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, NestedLocalRow, NestedHydratedRow, IsChildNullable, any>, keyBy: KeyBy<NestedLocalRow>): HydratedQueryBuilder<Prefix, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, LocalRow & ApplyPrefixes<MakePrefix<"", K$1>, NestedLocalRow>, Extend<HydratedRow, { [_ in K$1]: IsChildNullable extends true ? NestedHydratedRow | null : NestedHydratedRow }>, IsNullable, HasJoin>;
|
|
674
660
|
hasOne<K$1 extends string, JoinedQueryDB, JoinedQueryTB extends keyof JoinedQueryDB, JoinedQueryRow, NestedLocalDB, NestedLocalRow extends InputWithDefaultKey, NestedHydratedRow, IsChildNullable extends boolean>(key: K$1, jb: (nb: HydratedQueryBuilder<MakePrefix<Prefix, NoInfer<K$1>>, QueryDB, QueryTB, QueryRow, LocalDB, {},
|
|
675
661
|
// LocalRow is empty within the nesting.
|
|
676
662
|
{},
|
|
677
663
|
// HydratedRow is empty within the nesting.
|
|
678
|
-
false, false>) =>
|
|
664
|
+
false, false>) => MappedHydratedQueryBuilder<MakePrefix<Prefix, NoInfer<K$1>>, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, NestedLocalRow, NestedHydratedRow, IsChildNullable, any>): HydratedQueryBuilder<Prefix, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, LocalRow & ApplyPrefixes<MakePrefix<"", K$1>, NestedLocalRow>, Extend<HydratedRow, { [_ in K$1]: IsChildNullable extends true ? NestedHydratedRow | null : NestedHydratedRow }>, IsNullable, HasJoin>;
|
|
679
665
|
/**
|
|
680
666
|
* Exactly like {@link hasOne}, but throws an error if the nested object is not found.
|
|
681
667
|
*
|
|
@@ -689,12 +675,12 @@ interface HydratedQueryBuilder<Prefix extends string, QueryDB, QueryTB extends k
|
|
|
689
675
|
// LocalRow is empty within the nesting.
|
|
690
676
|
{},
|
|
691
677
|
// HydratedRow is empty within the nesting.
|
|
692
|
-
false, false>) =>
|
|
678
|
+
false, false>) => MappedHydratedQueryBuilder<MakePrefix<Prefix, NoInfer<K$1>>, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, NestedLocalRow, NestedHydratedRow, any, any>, keyBy: KeyBy<NestedLocalRow>): HydratedQueryBuilder<Prefix, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, LocalRow & ApplyPrefixes<MakePrefix<"", K$1>, NestedLocalRow>, Extend<HydratedRow, { [_ in K$1]: NestedHydratedRow }>, IsNullable, HasJoin>;
|
|
693
679
|
hasOneOrThrow<K$1 extends string, JoinedQueryDB, JoinedQueryTB extends keyof JoinedQueryDB, JoinedQueryRow, NestedLocalDB, NestedLocalRow extends InputWithDefaultKey, NestedHydratedRow>(key: K$1, jb: (nb: HydratedQueryBuilder<MakePrefix<Prefix, NoInfer<K$1>>, QueryDB, QueryTB, QueryRow, LocalDB, {},
|
|
694
680
|
// LocalRow is empty within the nesting.
|
|
695
681
|
{},
|
|
696
682
|
// HydratedRow is empty within the nesting.
|
|
697
|
-
false, false>) =>
|
|
683
|
+
false, false>) => MappedHydratedQueryBuilder<MakePrefix<Prefix, NoInfer<K$1>>, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, NestedLocalRow, NestedHydratedRow, any, any>): HydratedQueryBuilder<Prefix, JoinedQueryDB, JoinedQueryTB, JoinedQueryRow, NestedLocalDB, LocalRow & ApplyPrefixes<MakePrefix<"", K$1>, NestedLocalRow>, Extend<HydratedRow, { [_ in K$1]: NestedHydratedRow }>, IsNullable, HasJoin>;
|
|
698
684
|
/**
|
|
699
685
|
* Attaches data from an external source (not via SQL joins) as a nested array.
|
|
700
686
|
* The `fetchFn` is called exactly once per query execution with all parent rows
|
|
@@ -993,4 +979,4 @@ declare class KeyByMismatchError extends KyselyHydrateError {
|
|
|
993
979
|
constructor(thisKeyBy: string, otherKeyBy: string);
|
|
994
980
|
}
|
|
995
981
|
//#endregion
|
|
996
|
-
export { AmbiguousColumnReferenceError, ExpectedOneItemError, HydratePlugin, type Hydrator, InvalidInstanceError, KeyByMismatchError, KyselyHydrateError, UnexpectedCaseError, UnexpectedComplexAliasError, UnexpectedSelectAllError, UnexpectedSelectionTypeError, UnsupportedAliasNodeTypeError, UnsupportedNodeTypeError, UnsupportedTableAliasNodeTypeError, WildcardSelectionError, createHydrator, hydrate, hydrateData, map };
|
|
982
|
+
export { AmbiguousColumnReferenceError, ExpectedOneItemError, HydratePlugin, type Hydrator, InvalidInstanceError, KeyByMismatchError, KyselyHydrateError, UnexpectedCaseError, UnexpectedComplexAliasError, UnexpectedSelectAllError, UnexpectedSelectionTypeError, UnsupportedAliasNodeTypeError, UnsupportedNodeTypeError, UnsupportedTableAliasNodeTypeError, WildcardSelectionError, createHydrator, hydrate, hydrateData, isFullHydrator, map };
|
package/dist/index.mjs
CHANGED
|
@@ -240,105 +240,89 @@ const ensureFieldsAccessor = createPrivateAccessor();
|
|
|
240
240
|
* @internal
|
|
241
241
|
*/
|
|
242
242
|
const ensureFields = ensureFieldsAccessor.call;
|
|
243
|
+
const IsFullHydrator = Symbol("HydratorType");
|
|
243
244
|
/**
|
|
244
|
-
*
|
|
245
|
+
* Determines if a hydrator is a full hydrator, meaning it has not had a .map()
|
|
246
|
+
* applied to it yet.
|
|
245
247
|
*
|
|
246
|
-
*
|
|
247
|
-
*
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
248
|
+
* @param hydrator - The hydrator to check
|
|
249
|
+
* @returns True if the hydrator is a full hydrator, false otherwise
|
|
250
|
+
*/
|
|
251
|
+
const isFullHydrator = (hydrator) => {
|
|
252
|
+
return hydrator[IsFullHydrator];
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* Asserts that a hydrator is a full hydrator and returns it.
|
|
253
256
|
*
|
|
254
|
-
* @
|
|
255
|
-
* @template Output - The type of the hydrated output structure
|
|
257
|
+
* @internal
|
|
256
258
|
*/
|
|
257
|
-
|
|
259
|
+
const asFullHydrator = (hydrator) => {
|
|
260
|
+
if (isFullHydrator(hydrator)) return hydrator;
|
|
261
|
+
throw new Error("Hydrator is not a full hydrator");
|
|
262
|
+
};
|
|
263
|
+
/**
|
|
264
|
+
* Implements the entire inheritance chain of Hydrators.
|
|
265
|
+
*/
|
|
266
|
+
var HydratorImpl = class HydratorImpl {
|
|
258
267
|
#props;
|
|
259
268
|
constructor(props) {
|
|
260
269
|
this.#props = props;
|
|
261
270
|
ensureFieldsAccessor.register(this, this.#ensureFields.bind(this));
|
|
262
271
|
}
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
* @param fields - An object mapping field names to either `true` (include as-is)
|
|
267
|
-
* or a transformation function
|
|
268
|
-
* @returns A new Hydrator with the fields configuration merged
|
|
269
|
-
*/
|
|
272
|
+
get [IsFullHydrator]() {
|
|
273
|
+
return !this.#props.mapFns?.length;
|
|
274
|
+
}
|
|
270
275
|
fields(fields) {
|
|
271
|
-
return new
|
|
276
|
+
return new HydratorImpl({
|
|
272
277
|
...this.#props,
|
|
273
278
|
fields: addObjectToMap(this.#props.fields, fields)
|
|
274
279
|
});
|
|
275
280
|
}
|
|
276
|
-
/**
|
|
277
|
-
* Omits specified fields from the hydrated output.
|
|
278
|
-
*
|
|
279
|
-
* @param keys - Field names to omit from the output
|
|
280
|
-
* @returns A new Hydrator with the fields omitted
|
|
281
|
-
*/
|
|
282
281
|
omit(keys) {
|
|
283
282
|
const omitFields = Object.fromEntries(keys.map((key) => [key, false]));
|
|
284
|
-
return new
|
|
283
|
+
return new HydratorImpl({
|
|
285
284
|
...this.#props,
|
|
286
285
|
fields: addObjectToMap(this.#props.fields, omitFields)
|
|
287
286
|
});
|
|
288
287
|
}
|
|
289
|
-
/**
|
|
290
|
-
* Private method to ensure fields are included in the output if they don't
|
|
291
|
-
* already have an explicit configuration (including explicit omission).
|
|
292
|
-
* Used by HydratedQueryBuilder via the exported ensureFields helper function.
|
|
293
|
-
*/
|
|
294
288
|
#ensureFields(fieldNames) {
|
|
295
289
|
const clone = new Map(this.#props.fields);
|
|
296
290
|
for (const name of fieldNames) if (!clone.has(name)) clone.set(name, true);
|
|
297
|
-
return new
|
|
291
|
+
return new HydratorImpl({
|
|
298
292
|
...this.#props,
|
|
299
293
|
fields: clone
|
|
300
294
|
});
|
|
301
295
|
}
|
|
302
|
-
/**
|
|
303
|
-
* Configures extra computed fields to add to the hydrated output.
|
|
304
|
-
*
|
|
305
|
-
* @param extras - An object mapping field names to functions that compute
|
|
306
|
-
* the field value from the entire input
|
|
307
|
-
* @returns A new Hydrator with the extras configuration merged
|
|
308
|
-
*/
|
|
309
296
|
extras(extras) {
|
|
310
|
-
return new
|
|
297
|
+
return new HydratorImpl({
|
|
311
298
|
...this.#props,
|
|
312
299
|
extras: addObjectToMap(this.#props.extras, extras)
|
|
313
300
|
});
|
|
314
301
|
}
|
|
315
|
-
/**
|
|
316
|
-
* Extends this Hydrator with the configuration from another Hydrator. The
|
|
317
|
-
* other Hydrator's configuration takes precedence in case of conflicts.
|
|
318
|
-
*
|
|
319
|
-
* Both hydrators must have the same `keyBy`, and any overlapping fields
|
|
320
|
-
* between the two input types must have compatible types.
|
|
321
|
-
*
|
|
322
|
-
* @param other - The Hydrator to extend with
|
|
323
|
-
* @returns A new Hydrator with merged configuration
|
|
324
|
-
* @throws {KeyByMismatchError} If the keyBy configurations don't match
|
|
325
|
-
*/
|
|
326
302
|
extend(other) {
|
|
303
|
+
const otherImpl = other;
|
|
327
304
|
const thisKeyBy = JSON.stringify(this.#props.keyBy);
|
|
328
|
-
const otherKeyBy = JSON.stringify(
|
|
305
|
+
const otherKeyBy = JSON.stringify(otherImpl.#props.keyBy);
|
|
329
306
|
if (thisKeyBy !== otherKeyBy) throw new KeyByMismatchError(thisKeyBy, otherKeyBy);
|
|
330
307
|
const ownProps = this.#props;
|
|
331
|
-
const otherProps =
|
|
332
|
-
return new
|
|
308
|
+
const otherProps = otherImpl.#props;
|
|
309
|
+
return new HydratorImpl({
|
|
333
310
|
keyBy: otherProps.keyBy,
|
|
334
311
|
fields: new Map([...ownProps.fields ?? [], ...otherProps.fields ?? []]),
|
|
335
312
|
extras: new Map([...ownProps.extras ?? [], ...otherProps.extras ?? []]),
|
|
336
313
|
collections: new Map([...ownProps.collections ?? [], ...otherProps.collections ?? []]),
|
|
337
|
-
attachedCollections: new Map([...ownProps.attachedCollections ?? [], ...otherProps.attachedCollections ?? []])
|
|
314
|
+
attachedCollections: new Map([...ownProps.attachedCollections ?? [], ...otherProps.attachedCollections ?? []]),
|
|
315
|
+
mapFns: [...this.#props.mapFns ?? [], ...otherProps.mapFns ?? []]
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
map(fn) {
|
|
319
|
+
return new HydratorImpl({
|
|
320
|
+
...this.#props,
|
|
321
|
+
mapFns: [...this.#props.mapFns ?? [], fn]
|
|
338
322
|
});
|
|
339
323
|
}
|
|
340
324
|
has(mode, key, prefix, hydrator) {
|
|
341
|
-
return new
|
|
325
|
+
return new HydratorImpl({
|
|
342
326
|
...this.#props,
|
|
343
327
|
collections: new Map(this.#props.collections).set(key, {
|
|
344
328
|
prefix,
|
|
@@ -347,42 +331,17 @@ var Hydrator = class Hydrator {
|
|
|
347
331
|
})
|
|
348
332
|
});
|
|
349
333
|
}
|
|
350
|
-
/**
|
|
351
|
-
* Shorthand for `has("many", ...)` - configures a nested array collection.
|
|
352
|
-
*
|
|
353
|
-
* @param key - The key name for the collection in the output
|
|
354
|
-
* @param prefix - The prefix used in the input data (e.g., "posts$$")
|
|
355
|
-
* @param hydrator - The Hydrator configuration for the child entities
|
|
356
|
-
* @returns A new Hydrator with the nested collection added
|
|
357
|
-
*/
|
|
358
334
|
hasMany(key, prefix, hydrator) {
|
|
359
335
|
return this.has("many", key, prefix, hydrator);
|
|
360
336
|
}
|
|
361
|
-
/**
|
|
362
|
-
* Shorthand for `has("one", ...)` - configures a nested nullable single entity.
|
|
363
|
-
*
|
|
364
|
-
* @param key - The key name for the entity in the output
|
|
365
|
-
* @param prefix - The prefix used in the input data (e.g., "author$$")
|
|
366
|
-
* @param hydrator - The Hydrator configuration for the child entity
|
|
367
|
-
* @returns A new Hydrator with the nested entity added
|
|
368
|
-
*/
|
|
369
337
|
hasOne(key, prefix, hydrator) {
|
|
370
338
|
return this.has("one", key, prefix, hydrator);
|
|
371
339
|
}
|
|
372
|
-
/**
|
|
373
|
-
* Shorthand for `has("oneOrThrow", ...)` - configures a nested non-nullable single entity.
|
|
374
|
-
* Throws an error if the entity is not found during hydration.
|
|
375
|
-
*
|
|
376
|
-
* @param key - The key name for the entity in the output.
|
|
377
|
-
* @param prefix - The prefix used in the input data (e.g., "author$$").
|
|
378
|
-
* @param hydrator - The Hydrator configuration for the child entity.
|
|
379
|
-
* @returns A new Hydrator with the nested entity added.
|
|
380
|
-
*/
|
|
381
340
|
hasOneOrThrow(key, prefix, hydrator) {
|
|
382
341
|
return this.has("oneOrThrow", key, prefix, hydrator);
|
|
383
342
|
}
|
|
384
343
|
attach(mode, key, fetchFn, keys) {
|
|
385
|
-
return new
|
|
344
|
+
return new HydratorImpl({
|
|
386
345
|
...this.#props,
|
|
387
346
|
attachedCollections: new Map(this.#props.attachedCollections).set(key, {
|
|
388
347
|
mode,
|
|
@@ -392,40 +351,12 @@ var Hydrator = class Hydrator {
|
|
|
392
351
|
})
|
|
393
352
|
});
|
|
394
353
|
}
|
|
395
|
-
/**
|
|
396
|
-
* Shorthand for `attach("many", ...)` - configures an attached array collection.
|
|
397
|
-
*
|
|
398
|
-
* @param key - The property name for the collection in the output.
|
|
399
|
-
* @param fetchFn - A function that fetches and hydrates the attached data.
|
|
400
|
-
* @param keys.matchChild - The key(s) on the attached output to use for matching to parents.
|
|
401
|
-
* @param keys.toParent - The key(s) on the parent input to compare with the child's key.
|
|
402
|
-
* @returns A new Hydrator with the attached collection added.
|
|
403
|
-
*/
|
|
404
354
|
attachMany(key, fetchFn, keys) {
|
|
405
355
|
return this.attach("many", key, fetchFn, keys);
|
|
406
356
|
}
|
|
407
|
-
/**
|
|
408
|
-
* Shorthand for `attach("one", ...)` - configures an attached nullable single entity.
|
|
409
|
-
*
|
|
410
|
-
* @param key - The property name for the entity in the output.
|
|
411
|
-
* @param fetchFn - A function that fetches and hydrates the attached data.
|
|
412
|
-
* @param keys.matchChild - The key(s) on the attached output to use for matching to parents.
|
|
413
|
-
* @param keys.toParent - The key(s) on the parent input to compare with the child's key.
|
|
414
|
-
* @returns A new Hydrator with the attached entity added.
|
|
415
|
-
*/
|
|
416
357
|
attachOne(key, fetchFn, keys) {
|
|
417
358
|
return this.attach("one", key, fetchFn, keys);
|
|
418
359
|
}
|
|
419
|
-
/**
|
|
420
|
-
* Shorthand for `attach("oneOrThrow", ...)` - configures an attached non-nullable single entity.
|
|
421
|
-
* Throws an error if the entity is not found during hydration.
|
|
422
|
-
*
|
|
423
|
-
* @param key - The property name for the entity in the output
|
|
424
|
-
* @param fetchFn - A function that fetches and hydrates the attached data
|
|
425
|
-
* @param keys.matchChild - The key(s) on the attached output to use for matching to parents
|
|
426
|
-
* @param keys.toParent - The key(s) on the parent input to compare with the child's key.
|
|
427
|
-
* @returns A new Hydrator with the attached entity added
|
|
428
|
-
*/
|
|
429
360
|
attachOneOrThrow(key, fetchFn, keys) {
|
|
430
361
|
return this.attach("oneOrThrow", key, fetchFn, keys);
|
|
431
362
|
}
|
|
@@ -483,6 +414,12 @@ var Hydrator = class Hydrator {
|
|
|
483
414
|
const attachedRows = attachedDataMap.get(mapKey)?.get(inputKey);
|
|
484
415
|
entity[key] = applyCollectionMode(attachedRows, collection.mode, key);
|
|
485
416
|
}
|
|
417
|
+
const { mapFns } = this.#props;
|
|
418
|
+
if (mapFns) {
|
|
419
|
+
let result = entity;
|
|
420
|
+
for (const mapFn of mapFns) result = mapFn(result);
|
|
421
|
+
return result;
|
|
422
|
+
}
|
|
486
423
|
return entity;
|
|
487
424
|
}
|
|
488
425
|
/**
|
|
@@ -519,7 +456,7 @@ var Hydrator = class Hydrator {
|
|
|
519
456
|
}
|
|
520
457
|
};
|
|
521
458
|
function createHydrator(keyBy) {
|
|
522
|
-
return new
|
|
459
|
+
return new HydratorImpl({ keyBy: keyBy ?? DEFAULT_KEY_BY });
|
|
523
460
|
}
|
|
524
461
|
function hydrateData(input, hydrator) {
|
|
525
462
|
hydrator = typeof hydrator === "function" ? hydrator(createHydrator) : hydrator;
|
|
@@ -621,9 +558,8 @@ function extractSelectionName(selectionNode) {
|
|
|
621
558
|
//#endregion
|
|
622
559
|
//#region src/query-builder.ts
|
|
623
560
|
/**
|
|
624
|
-
* Implementation of the {@link HydratedQueryBuilder} interface
|
|
625
|
-
*
|
|
626
|
-
* @internal
|
|
561
|
+
* Implementation of the {@link HydratedQueryBuilder} interface as well as the
|
|
562
|
+
* {@link MappedHydratedQueryBuilder} interface; there is no runtime distinction.
|
|
627
563
|
*/
|
|
628
564
|
var HydratedQueryBuilderImpl = class HydratedQueryBuilderImpl {
|
|
629
565
|
#props;
|
|
@@ -642,9 +578,7 @@ var HydratedQueryBuilderImpl = class HydratedQueryBuilderImpl {
|
|
|
642
578
|
toOperationNode() {
|
|
643
579
|
return this.#props.qb.toOperationNode();
|
|
644
580
|
}
|
|
645
|
-
_generics() {
|
|
646
|
-
return this;
|
|
647
|
-
}
|
|
581
|
+
get _generics() {}
|
|
648
582
|
modify(modifier) {
|
|
649
583
|
return new HydratedQueryBuilderImpl({
|
|
650
584
|
...this.#props,
|
|
@@ -654,28 +588,10 @@ var HydratedQueryBuilderImpl = class HydratedQueryBuilderImpl {
|
|
|
654
588
|
toQuery() {
|
|
655
589
|
return this.#props.qb;
|
|
656
590
|
}
|
|
657
|
-
|
|
658
|
-
return new HydratedQueryBuilderImpl({
|
|
659
|
-
...this.#props,
|
|
660
|
-
hydrator: this.#props.hydrator.extras(extras)
|
|
661
|
-
});
|
|
662
|
-
}
|
|
663
|
-
mapFields(mappings) {
|
|
591
|
+
map(transform) {
|
|
664
592
|
return new HydratedQueryBuilderImpl({
|
|
665
593
|
...this.#props,
|
|
666
|
-
hydrator: this.#props.hydrator.
|
|
667
|
-
});
|
|
668
|
-
}
|
|
669
|
-
omit(keys) {
|
|
670
|
-
return new HydratedQueryBuilderImpl({
|
|
671
|
-
...this.#props,
|
|
672
|
-
hydrator: this.#props.hydrator.omit(keys)
|
|
673
|
-
});
|
|
674
|
-
}
|
|
675
|
-
with(hydrator) {
|
|
676
|
-
return new HydratedQueryBuilderImpl({
|
|
677
|
-
...this.#props,
|
|
678
|
-
hydrator: this.#props.hydrator.extend(hydrator)
|
|
594
|
+
hydrator: this.#props.hydrator.map(transform)
|
|
679
595
|
});
|
|
680
596
|
}
|
|
681
597
|
#hydrate(rows) {
|
|
@@ -697,6 +613,30 @@ var HydratedQueryBuilderImpl = class HydratedQueryBuilderImpl {
|
|
|
697
613
|
const result = await this.#props.qb.executeTakeFirstOrThrow(errorConstructor);
|
|
698
614
|
return this.#hydrate(result);
|
|
699
615
|
}
|
|
616
|
+
extras(extras) {
|
|
617
|
+
return new HydratedQueryBuilderImpl({
|
|
618
|
+
...this.#props,
|
|
619
|
+
hydrator: asFullHydrator(this.#props.hydrator).extras(extras)
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
mapFields(mappings) {
|
|
623
|
+
return new HydratedQueryBuilderImpl({
|
|
624
|
+
...this.#props,
|
|
625
|
+
hydrator: asFullHydrator(this.#props.hydrator).fields(mappings)
|
|
626
|
+
});
|
|
627
|
+
}
|
|
628
|
+
omit(keys) {
|
|
629
|
+
return new HydratedQueryBuilderImpl({
|
|
630
|
+
...this.#props,
|
|
631
|
+
hydrator: asFullHydrator(this.#props.hydrator).omit(keys)
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
with(hydrator) {
|
|
635
|
+
return new HydratedQueryBuilderImpl({
|
|
636
|
+
...this.#props,
|
|
637
|
+
hydrator: asFullHydrator(this.#props.hydrator).extend(hydrator)
|
|
638
|
+
});
|
|
639
|
+
}
|
|
700
640
|
#addJoin(mode, key, jb, keyBy = DEFAULT_KEY_BY) {
|
|
701
641
|
const outputNb = jb(new HydratedQueryBuilderImpl({
|
|
702
642
|
qb: this.#props.qb,
|
|
@@ -706,7 +646,7 @@ var HydratedQueryBuilderImpl = class HydratedQueryBuilderImpl {
|
|
|
706
646
|
return new HydratedQueryBuilderImpl({
|
|
707
647
|
...this.#props,
|
|
708
648
|
qb: outputNb.#props.qb,
|
|
709
|
-
hydrator: this.#props.hydrator.has(mode, key, makePrefix("", key), outputNb.#props.hydrator)
|
|
649
|
+
hydrator: asFullHydrator(this.#props.hydrator).has(mode, key, makePrefix("", key), outputNb.#props.hydrator)
|
|
710
650
|
});
|
|
711
651
|
}
|
|
712
652
|
hasMany(key, jb, keyBy) {
|
|
@@ -721,7 +661,7 @@ var HydratedQueryBuilderImpl = class HydratedQueryBuilderImpl {
|
|
|
721
661
|
#addAttach(mode, key, fetchFn, keys) {
|
|
722
662
|
return new HydratedQueryBuilderImpl({
|
|
723
663
|
...this.#props,
|
|
724
|
-
hydrator: this.#props.hydrator.attach(mode, key, fetchFn, keys)
|
|
664
|
+
hydrator: asFullHydrator(this.#props.hydrator).attach(mode, key, fetchFn, keys)
|
|
725
665
|
});
|
|
726
666
|
}
|
|
727
667
|
attachMany(key, fetchFn, keys) {
|
|
@@ -738,7 +678,7 @@ var HydratedQueryBuilderImpl = class HydratedQueryBuilderImpl {
|
|
|
738
678
|
return new HydratedQueryBuilderImpl({
|
|
739
679
|
...this.#props,
|
|
740
680
|
qb: this.#props.qb.select(prefixedSelections),
|
|
741
|
-
hydrator: this.#props.hydrator.fields(Object.fromEntries(prefixedSelections.map((selection$1) => [selection$1.originalName, true])))
|
|
681
|
+
hydrator: asFullHydrator(this.#props.hydrator).fields(Object.fromEntries(prefixedSelections.map((selection$1) => [selection$1.originalName, true])))
|
|
742
682
|
});
|
|
743
683
|
}
|
|
744
684
|
innerJoin(...args) {
|
|
@@ -1160,4 +1100,4 @@ var HydratePlugin = class {
|
|
|
1160
1100
|
};
|
|
1161
1101
|
|
|
1162
1102
|
//#endregion
|
|
1163
|
-
export { AmbiguousColumnReferenceError, ExpectedOneItemError, HydratePlugin, InvalidInstanceError, KeyByMismatchError, KyselyHydrateError, UnexpectedCaseError, UnexpectedComplexAliasError, UnexpectedSelectAllError, UnexpectedSelectionTypeError, UnsupportedAliasNodeTypeError, UnsupportedNodeTypeError, UnsupportedTableAliasNodeTypeError, WildcardSelectionError, createHydrator, hydrate, hydrateData, map };
|
|
1103
|
+
export { AmbiguousColumnReferenceError, ExpectedOneItemError, HydratePlugin, InvalidInstanceError, KeyByMismatchError, KyselyHydrateError, UnexpectedCaseError, UnexpectedComplexAliasError, UnexpectedSelectAllError, UnexpectedSelectionTypeError, UnsupportedAliasNodeTypeError, UnsupportedNodeTypeError, UnsupportedTableAliasNodeTypeError, WildcardSelectionError, createHydrator, hydrate, hydrateData, isFullHydrator, map };
|