Skip to content

Commit 6c56f1d

Browse files
committed
checkpoint
1 parent d5921a4 commit 6c56f1d

File tree

1 file changed

+48
-21
lines changed

1 file changed

+48
-21
lines changed

packages/db/src/query/builder/types.ts

Lines changed: 48 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -127,25 +127,35 @@ export type WhereCallback<TContext extends Context> = (
127127
* SelectValue - Union of all valid values in a select clause
128128
*
129129
* This type defines what can be used as values in the object passed to `select()`.
130-
* It includes:
131130
*
132131
* **Core Expression Types**:
133132
* - `BasicExpression`: Function calls like `upper(users.name)`
134133
* - `Aggregate`: Aggregations like `count()`, `avg()`
135134
* - `RefProxy/Ref`: Direct field references like `users.name`
136135
*
136+
* **JavaScript Literals** (for constant values in projections):
137+
* - `string`: String literals like `'active'`, `'N/A'`
138+
* - `number`: Numeric literals like `0`, `42`, `3.14`
139+
* - `boolean`: Boolean literals `true`, `false`
140+
* - `null`: Explicit null values
141+
*
137142
* **Advanced Features**:
138143
* - `undefined`: Allows optional projection values
139144
* - `{ [key: string]: SelectValue }`: Nested object projection
140145
* - `PrecomputeRefStructure<any>`: Spread operations like `...users`
141146
*
142-
* **Internal Support** (for spread operations):
143-
* - `true`, `Array<string>`, `any`: Allow RefProxy internal properties to pass through
147+
* Note: The runtime spread implementation uses internal RefProxy properties
148+
* but these are hidden from the type system for cleaner typing.
144149
*
145-
* The nested object support enables projections like:
150+
* Examples:
146151
* ```typescript
147152
* select({
148153
* id: users.id,
154+
* name: users.name,
155+
* status: 'active', // string literal
156+
* priority: 1, // number literal
157+
* verified: true, // boolean literal
158+
* notes: null, // explicit null
149159
* profile: {
150160
* name: users.name,
151161
* email: users.email
@@ -159,13 +169,14 @@ type SelectValue =
159169
| RefProxy
160170
| RefProxyFor<any>
161171
| Ref<any>
162-
| undefined
172+
| string // String literals
173+
| number // Numeric literals
174+
| boolean // Boolean literals
175+
| null // Explicit null
176+
| undefined // Optional values
163177
| { [key: string]: SelectValue }
164178
| PrecomputeRefStructure<any>
165179
| Array<Ref<any>>
166-
| true // For __refProxy property in spreads
167-
| Array<string> // For __path property in spreads
168-
| any // For __type property in spreads
169180

170181
/**
171182
* SelectObject - Wrapper type for select clause objects
@@ -194,6 +205,12 @@ export type SelectObject<
194205
* - `BasicExpression<T>` → `T`: Function results like `upper()` → `string`
195206
* - `Aggregate<T>` → `T`: Aggregation results like `count()` → `number`
196207
*
208+
* **JavaScript Literals** (pass through as-is):
209+
* - `string` → `string`: String literals remain strings
210+
* - `number` → `number`: Numeric literals remain numbers
211+
* - `boolean` → `boolean`: Boolean literals remain booleans
212+
* - `null` → `null`: Explicit null remains null
213+
*
197214
* **Nested Objects** (recursive):
198215
* - Plain objects are recursively processed to handle nested projections
199216
* - RefProxy objects are detected and excluded from recursion
@@ -205,10 +222,10 @@ export type SelectObject<
205222
* Example transformation:
206223
* ```typescript
207224
* // Input:
208-
* { id: Ref<number>, name: Ref<string>, profile: { bio: Ref<string> } }
225+
* { id: Ref<number>, name: Ref<string>, status: 'active', count: 42, profile: { bio: Ref<string> } }
209226
*
210227
* // Output:
211-
* { id: number, name: string, profile: { bio: string } }
228+
* { id: number, name: string, status: 'active', count: 42, profile: { bio: string } }
212229
* ```
213230
*/
214231
export type ResultTypeFromSelect<TSelectObject> = {
@@ -230,6 +247,14 @@ export type ResultTypeFromSelect<TSelectObject> = {
230247
? T
231248
: TSelectObject[K] extends RefProxyFor<infer T>
232249
? T
250+
: TSelectObject[K] extends string
251+
? string
252+
: TSelectObject[K] extends number
253+
? number
254+
: TSelectObject[K] extends boolean
255+
? boolean
256+
: TSelectObject[K] extends null
257+
? null
233258
: TSelectObject[K] extends undefined
234259
? undefined
235260
: TSelectObject[K] extends { __type: infer U }
@@ -481,6 +506,7 @@ export type RefProxyFor<T> = IsExactlyUndefined<T> extends true
481506
* 2. **Recursive structure**: Object properties become nested RefProxy/Ref types
482507
* 3. **Optionality handling**: undefined/null are placed outside refs for ?. support
483508
* 4. **Type preservation**: The structure mirrors the original type as closely as possible
509+
* 5. **Spread support**: Internal properties are hidden during spread operations
484510
*
485511
* Examples:
486512
* RefProxy<string> → { __refProxy: true, __path: [...], __type: string }
@@ -493,6 +519,7 @@ export type RefProxyFor<T> = IsExactlyUndefined<T> extends true
493519
* - For primitive types: Only internal metadata is added
494520
* - For object types: Properties are recursively transformed with optionality preserved
495521
* - For undefined: No additional properties (just metadata)
522+
* - For spreads: Internal properties are excluded from type checking
496523
*/
497524
export type RefProxy<T = any> = {
498525
/** @internal - Runtime marker to identify ref proxy objects */
@@ -526,19 +553,19 @@ export type RefProxy<T = any> = {
526553
/**
527554
* Ref - The user-facing ref type with clean IDE display
528555
*
529-
* This is what users see in their IDE and what they use in composable functions.
530-
* It's actually just an alias for RefProxy<T>, but TypeScript displays it cleanly as "Ref<T>"
531-
* instead of showing all the internal RefProxy properties.
556+
* This is just an alias for RefProxy<T> but provides a cleaner name that
557+
* TypeScript will prefer to display in most contexts. While not a perfect
558+
* solution for hiding internal structure, it provides better semantics.
532559
*
533560
* Examples in IDE:
534-
* - Ref<string> instead of { __refProxy: true; __path: Array<string>; __type: string }
535-
* - Ref<User> instead of the full RefProxy<User> structure
536-
*
537-
* This unification means:
538-
* 1. Users get a clean API: all composables use Ref<T>
539-
* 2. Full functionality: Ref<T> has all RefProxy properties due to the alias
540-
* 3. Type compatibility: Ref<T> and RefProxy<T> are interchangeable
541-
* 4. Better DX: IDEs show meaningful type names instead of complex structures
561+
* - Ref<string> (when TypeScript chooses to show the alias name)
562+
* - RefProxy internals (when TypeScript expands the type)
563+
*
564+
* This alias approach means:
565+
* 1. Users get a semantic API: all composables use Ref<T>
566+
* 2. Full compatibility: Ref<T> is exactly RefProxy<T>
567+
* 3. Type safety: No additional compatibility issues
568+
* 4. Cleaner imports: Users import Ref instead of RefProxy
542569
*/
543570
export type Ref<T> = RefProxy<T>
544571

0 commit comments

Comments
 (0)