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 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<{ id: number; username: string; displayName: string }>;
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. This method
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
- .fields({ email: true })
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>): Hydrator<Input, {}>;
107
+ (keyBy: KeyBy<Input>): FullHydrator<Input, {}>;
192
108
  }
193
109
  interface CreateHydratorWithDefaultKey<Input> extends CreateHydratorWithoutDefaultKey<Input> {
194
- (): Hydrator<Input, {}>;
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>) => Hydrator<Input, Output>;
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> = Hydrator<Input, Output> | HydratorFactory<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> = Hydrator<SelectAndStripPrefix<P, ParentInput>, ChildOutput> | ((create: CreateHydratorFn<SelectAndStripPrefix<P, ParentInput>>) => Hydrator<SelectAndStripPrefix<P, 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
- declare class Hydrator<Input, Output> {
243
- #private;
244
- constructor(props: HydratorProps<Input>);
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): Hydrator<Input, Extend<Output, InferFields<Input, 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[]): Hydrator<Input, Omit<Output, 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): Hydrator<Input, Extend<Output, InferExtras<Input, 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: Hydrator<OtherInput, OtherOutput>): Hydrator<Input & OtherInput, Extend<Output, OtherOutput>>;
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>): Hydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput[] }>>;
297
- has<K$1 extends string, P extends string, ChildOutput>(mode: "one", key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): Hydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput | null }>>;
298
- has<K$1 extends string, P extends string, ChildOutput>(mode: "oneOrThrow", key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): Hydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput }>>;
299
- has<K$1 extends string, P extends string, ChildOutput>(mode: CollectionMode, key: K$1, prefix: P, hydrator: ChildHydratorArg<P, Input, ChildOutput>): Hydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput[] | ChildOutput | null }>>;
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>): Hydrator<Input, Extend<Output, { [_ in K$1]: 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>): Hydrator<Input, Extend<Output, { [_ in K$1]: ChildOutput | null }>>;
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>): Hydrator<Input, Extend<Output, { [_ in K$1]: 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>): Hydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput[] }>>;
348
- attach<K$1 extends string, AttachedOutput>(mode: "one", key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): Hydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput | null }>>;
349
- attach<K$1 extends string, AttachedOutput>(mode: "oneOrThrow", key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): Hydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput }>>;
350
- attach<K$1 extends string, AttachedOutput>(mode: CollectionMode, key: K$1, fetchFn: FetchFn<Input, AttachedOutput>, keys: AttachedKeysArg<Input, AttachedOutput>): Hydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput[] | AttachedOutput | null }>>;
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>): Hydrator<Input, Extend<Output, { [_ in K$1]: 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>): Hydrator<Input, Extend<Output, { [_ in K$1]: AttachedOutput | null }>>;
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>): Hydrator<Input, Extend<Output, { [_ in K$1]: 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>>): Hydrator<T, {}>;
403
- declare function createHydrator<T extends InputWithDefaultKey>(): Hydrator<T, {}>;
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: Hydrator<OtherInput, OtherOutput>): HydratedQueryBuilder<Prefix, QueryDB, QueryTB, QueryRow, LocalDB, LocalRow, Extend<HydratedRow, OtherOutput>, IsNullable, HasJoin>;
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>) => HydratedQueryBuilder<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>;
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>) => HydratedQueryBuilder<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>;
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>) => HydratedQueryBuilder<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>;
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>) => HydratedQueryBuilder<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>;
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>) => HydratedQueryBuilder<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>;
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>) => HydratedQueryBuilder<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>;
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
- * A configuration for how to hydrate flat database rows into a denormalized structure.
245
+ * Determines if a hydrator is a full hydrator, meaning it has not had a .map()
246
+ * applied to it yet.
245
247
  *
246
- * The Hydrator class provides a fluent API for configuring:
247
- * - Fields to include (with optional transformations)
248
- * - Extra computed fields
249
- * - Nested collections (using `has()` methods)
250
- * - Attached collections (using `attach()` methods)
251
- *
252
- * Once configured, call `hydrate()` to transform input data into the denormalized output.
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
- * @template Input - The type of the input data (typically from a database query)
255
- * @template Output - The type of the hydrated output structure
257
+ * @internal
256
258
  */
257
- var Hydrator = class Hydrator {
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
- * Configures which fields to include in the hydrated output.
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 Hydrator({
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 Hydrator({
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 Hydrator({
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 Hydrator({
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(other.#props.keyBy);
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 = other.#props;
332
- return new Hydrator({
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 Hydrator({
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 Hydrator({
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 Hydrator({ keyBy: keyBy ?? DEFAULT_KEY_BY });
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
- extras(extras) {
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.fields(mappings)
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 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kysely-hydrate",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Explicit ORM-style queries with Kysely",
5
5
  "license": "MIT",
6
6
  "author": {