@@ -34,44 +34,39 @@ export interface TableSpec<App> {
3434}
3535
3636/**
37- * `select: { id: true, name: true }` — read those fields and nothing else.
38- * Same shape and same inference as the GraphQL ORM's select.
39- */
40- export type SelectShape < App > = { [ K in keyof App ] ?: boolean } ;
41-
42- /**
43- * `omit: { databaseId: true }` — read the record except those fields, for the
44- * field a record has in general but this binding's table does not (a scope's
45- * copy of a table without the scope key column) or that a caller must not
46- * carry (a secret's id, row bookkeeping). Prisma's `omit`, and the reason it
47- * exists there too: naming everything else is not the same statement.
37+ * Select shape — same as the GraphQL ORM, stated either way round:
38+ *
39+ * - `{ id: true, name: true }` reads those fields and nothing else;
40+ * - `{ databaseId: false }` reads every field except that one, for the field a
41+ * record has in general but this binding's table does not (a scope's copy of
42+ * a table without the scope key column) or that a caller must not carry (a
43+ * secret's id, row bookkeeping).
4844 *
49- * Mutually exclusive with `select` — a projection already says what it reads.
45+ * Naming a field `true` is a projection and wins outright: the excluded ones
46+ * are simply not in it.
5047 */
51- export type OmitShape < App > = { [ K in keyof App ] ?: boolean } ;
48+ export type SelectShape < App > = { [ K in keyof App ] ?: boolean } ;
5249
5350type TrueKeys < App , S > = {
5451 [ K in keyof S ] -?: S [ K ] extends true ? K & keyof App : never ;
5552} [ keyof S ] ;
5653
57- /** The record minus what `omit` names, which is the record when it names none. */
58- type OmitResult < App , O > = O extends OmitShape < App >
59- ? [ TrueKeys < App , O > ] extends [ never ]
60- ? App
61- : Omit < App , TrueKeys < App , O > >
62- : App ;
63-
64- /** Rows narrow to what the args state: `select` picks, `omit` subtracts. */
65- export type SelectResult <
66- App ,
67- S extends SelectShape < App > | undefined ,
68- O extends OmitShape < App > | undefined = undefined
69- > =
54+ type FalseKeys < App , S > = {
55+ [ K in keyof S ] -?: S [ K ] extends false ? K & keyof App : never ;
56+ } [ keyof S ] ;
57+
58+ /**
59+ * Rows narrow to what the select states: the picked fields, else the record
60+ * minus the excluded ones. No `select` returns the full record.
61+ */
62+ export type SelectResult < App , S extends SelectShape < App > | undefined > =
7063 S extends SelectShape < App >
7164 ? [ TrueKeys < App , S > ] extends [ never ]
72- ? OmitResult < App , O >
65+ ? [ FalseKeys < App , S > ] extends [ never ]
66+ ? App
67+ : Omit < App , FalseKeys < App , S > >
7368 : Pick < App , TrueKeys < App , S > >
74- : OmitResult < App , O > ;
69+ : App ;
7570
7671/** Per-field operators from the shared query-spec grammar. */
7772export interface FieldOps < V > {
@@ -148,62 +143,34 @@ export type OrderDirection = 'ASC' | 'DESC';
148143/** Order spec keyed by camelCase field names, e.g. `{ createdAt: 'DESC' }`. */
149144export type OrderBy < App > = { [ K in keyof App ] ?: OrderDirection } ;
150145
151- /**
152- * What a call reads. `select` and `omit` are alternatives, not layers, and
153- * stating both is refused at the call rather than silently resolved.
154- */
155- export interface Projection <
156- App ,
157- S extends SelectShape < App > | undefined ,
158- O extends OmitShape < App > | undefined
159- > {
160- select ?: S ;
161- omit ?: O ;
162- }
163-
164- export interface FindManyArgs <
165- App ,
166- S extends SelectShape < App > | undefined ,
167- O extends OmitShape < App > | undefined
168- > extends Projection < App , S , O > {
146+ export interface FindManyArgs < App , S extends SelectShape < App > | undefined > {
169147 where ?: Where < App > ;
148+ select ?: S ;
170149 orderBy ?: OrderBy < App > | OrderBy < App > [ ] ;
171150 limit ?: number ;
172151 offset ?: number ;
173152}
174153
175- export interface FindFirstArgs <
176- App ,
177- S extends SelectShape < App > | undefined ,
178- O extends OmitShape < App > | undefined
179- > extends Projection < App , S , O > {
154+ export interface FindFirstArgs < App , S extends SelectShape < App > | undefined > {
180155 where ?: Where < App > ;
156+ select ?: S ;
181157 orderBy ?: OrderBy < App > | OrderBy < App > [ ] ;
182158}
183159
184- export interface CreateArgs <
185- App ,
186- S extends SelectShape < App > | undefined ,
187- O extends OmitShape < App > | undefined
188- > extends Projection < App , S , O > {
160+ export interface CreateArgs < App , S extends SelectShape < App > | undefined > {
189161 data : Data < App > ;
162+ select ?: S ;
190163}
191164
192- export interface UpdateArgs <
193- App ,
194- S extends SelectShape < App > | undefined ,
195- O extends OmitShape < App > | undefined
196- > extends Projection < App , S , O > {
165+ export interface UpdateArgs < App , S extends SelectShape < App > | undefined > {
197166 where : Where < App > ;
198167 data : Data < App > ;
168+ select ?: S ;
199169}
200170
201- export interface DeleteArgs <
202- App ,
203- S extends SelectShape < App > | undefined ,
204- O extends OmitShape < App > | undefined
205- > extends Projection < App , S , O > {
171+ export interface DeleteArgs < App , S extends SelectShape < App > | undefined > {
206172 where : Where < App > ;
173+ select ?: S ;
207174}
208175
209176/** Thrown by `findFirstOrThrow` / `updateOrThrow` when no row matches. */
@@ -230,11 +197,10 @@ export class TableClient<App> {
230197 private readonly db : Queryable
231198 ) { }
232199
233- async findMany <
234- S extends SelectShape < App > | undefined = undefined ,
235- O extends OmitShape < App > | undefined = undefined
236- > ( args : FindManyArgs < App , S , O > = { } ) : Promise < SelectResult < App , S , O > [ ] > {
237- const fields = this . selectedFields ( args ) ;
200+ async findMany < S extends SelectShape < App > | undefined = undefined > (
201+ args : FindManyArgs < App , S > = { }
202+ ) : Promise < SelectResult < App , S > [ ] > {
203+ const fields = this . selectedFields ( args . select ) ;
238204 const query = this . baseQuery ( ) . select ( fields . map ( field => this . column ( field ) ) ) ;
239205 const predicate = this . predicate ( args . where ) ;
240206 if ( predicate ) query . where ( predicate ) ;
@@ -246,18 +212,16 @@ export class TableClient<App> {
246212 return rows . map ( row => this . decodeRow ( row , fields ) ) ;
247213 }
248214
249- async findFirst <
250- S extends SelectShape < App > | undefined = undefined ,
251- O extends OmitShape < App > | undefined = undefined
252- > ( args : FindFirstArgs < App , S , O > = { } ) : Promise < SelectResult < App , S , O > | null > {
253- const rows = await this . findMany < S , O > ( { ...args , limit : 1 } ) ;
215+ async findFirst < S extends SelectShape < App > | undefined = undefined > (
216+ args : FindFirstArgs < App , S > = { }
217+ ) : Promise < SelectResult < App , S > | null > {
218+ const rows = await this . findMany ( { ...args , limit : 1 } ) ;
254219 return rows . length > 0 ? rows [ 0 ] : null ;
255220 }
256221
257- async findFirstOrThrow <
258- S extends SelectShape < App > | undefined = undefined ,
259- O extends OmitShape < App > | undefined = undefined
260- > ( args : FindFirstArgs < App , S , O > = { } ) : Promise < SelectResult < App , S , O > > {
222+ async findFirstOrThrow < S extends SelectShape < App > | undefined = undefined > (
223+ args : FindFirstArgs < App , S > = { }
224+ ) : Promise < SelectResult < App , S > > {
261225 const row = await this . findFirst ( args ) ;
262226 if ( row === null ) throw new RowNotFoundError ( this . spec . table , 'findFirstOrThrow' ) ;
263227 return row ;
@@ -273,11 +237,10 @@ export class TableClient<App> {
273237 return Number ( row . count ) ;
274238 }
275239
276- async create <
277- S extends SelectShape < App > | undefined = undefined ,
278- O extends OmitShape < App > | undefined = undefined
279- > ( args : CreateArgs < App , S , O > ) : Promise < SelectResult < App , S , O > > {
280- const fields = this . selectedFields ( args ) ;
240+ async create < S extends SelectShape < App > | undefined = undefined > (
241+ args : CreateArgs < App , S >
242+ ) : Promise < SelectResult < App , S > > {
243+ const fields = this . selectedFields ( args . select ) ;
281244 const query = this . baseQuery ( )
282245 . insert ( this . encodeData ( args . data ) )
283246 . returning ( fields . map ( field => this . column ( field ) ) ) ;
@@ -286,11 +249,10 @@ export class TableClient<App> {
286249 return this . decodeRow ( rows [ 0 ] , fields ) ;
287250 }
288251
289- async update <
290- S extends SelectShape < App > | undefined = undefined ,
291- O extends OmitShape < App > | undefined = undefined
292- > ( args : UpdateArgs < App , S , O > ) : Promise < SelectResult < App , S , O > [ ] > {
293- const fields = this . selectedFields ( args ) ;
252+ async update < S extends SelectShape < App > | undefined = undefined > (
253+ args : UpdateArgs < App , S >
254+ ) : Promise < SelectResult < App , S > [ ] > {
255+ const fields = this . selectedFields ( args . select ) ;
294256 const query = this . baseQuery ( )
295257 . update ( this . encodeData ( args . data ) )
296258 . where ( this . required ( args . where , 'update' ) )
@@ -300,20 +262,18 @@ export class TableClient<App> {
300262 return rows . map ( row => this . decodeRow ( row , fields ) ) ;
301263 }
302264
303- async updateOrThrow <
304- S extends SelectShape < App > | undefined = undefined ,
305- O extends OmitShape < App > | undefined = undefined
306- > ( args : UpdateArgs < App , S , O > ) : Promise < SelectResult < App , S , O > > {
265+ async updateOrThrow < S extends SelectShape < App > | undefined = undefined > (
266+ args : UpdateArgs < App , S >
267+ ) : Promise < SelectResult < App , S > > {
307268 const rows = await this . update ( args ) ;
308269 if ( rows . length === 0 ) throw new RowNotFoundError ( this . spec . table , 'updateOrThrow' ) ;
309270 return rows [ 0 ] ;
310271 }
311272
312- async delete <
313- S extends SelectShape < App > | undefined = undefined ,
314- O extends OmitShape < App > | undefined = undefined
315- > ( args : DeleteArgs < App , S , O > ) : Promise < SelectResult < App , S , O > [ ] > {
316- const fields = this . selectedFields ( args ) ;
273+ async delete < S extends SelectShape < App > | undefined = undefined > (
274+ args : DeleteArgs < App , S >
275+ ) : Promise < SelectResult < App , S > [ ] > {
276+ const fields = this . selectedFields ( args . select ) ;
317277 const query = this . baseQuery ( )
318278 . delete ( )
319279 . where ( this . required ( args . where , 'delete' ) )
@@ -336,34 +296,26 @@ export class TableClient<App> {
336296 return this . spec . columnByField [ field ] ?? field ;
337297 }
338298
339- private selectedFields ( args : {
340- select ?: SelectShape < App > ;
341- omit ?: OmitShape < App > ;
342- } ) : ( keyof App & string ) [ ] {
299+ private selectedFields ( select : SelectShape < App > | undefined ) : ( keyof App & string ) [ ] {
343300 const all = Object . keys ( this . spec . columnByField ) as ( keyof App & string ) [ ] ;
344- if ( args . select && args . omit ) {
345- throw new Error (
346- `${ this . spec . table } : state either 'select' or 'omit' — a projection already says what it reads.`
347- ) ;
348- }
349- if ( args . select ) {
350- const picked = all . filter ( field => args . select ! [ field ] === true ) ;
351- if ( picked . length > 0 ) return picked ;
352- }
353- if ( args . omit ) return all . filter ( field => args . omit ! [ field ] !== true ) ;
354- return all ;
301+ if ( ! select ) return all ;
302+ const picked = all . filter ( field => select [ field ] === true ) ;
303+ if ( picked . length > 0 ) return picked ;
304+ // Nothing picked: the select either excludes fields or says nothing at all,
305+ // and both read what is left.
306+ return all . filter ( field => select [ field ] !== false ) ;
355307 }
356308
357- private decodeRow < S extends SelectShape < App > | undefined , O extends OmitShape < App > | undefined > (
309+ private decodeRow < S extends SelectShape < App > | undefined > (
358310 row : unknown ,
359311 fields : ( keyof App & string ) [ ]
360- ) : SelectResult < App , S , O > {
312+ ) : SelectResult < App , S > {
361313 const raw = row as Record < string , unknown > ;
362314 const decoded : Record < string , unknown > = { } ;
363315 for ( const field of fields ) {
364316 decoded [ field ] = this . spec . fields [ field ] ( raw [ this . column ( field ) ] ) ;
365317 }
366- return decoded as SelectResult < App , S , O > ;
318+ return decoded as SelectResult < App , S > ;
367319 }
368320
369321 /**
0 commit comments