/**
 * The type tests in this file can be run using `tsd`. Even though the unit
 * and integration tests should test most of the typings as well, this file is
 * needed to test some tricky typings that, if broken, don't necessarily show
 * up in the unit or integration tests. For example if the typings are broken
 * in a way that produces `any` types, the unit and integration tests are
 * happy, but we can catch it here.
 */ import { Kysely , Transaction , InsertResult , UpdateResult , DeleteResult , Generated , Selectable , ColumnType , } from '.' ; import { expectType , expectError , expectAssignable } from 'tsd' ; interface Person { id : Generated < number > ; first_name : string ; last_name : string | null ; age : number ; gender : 'male' | 'female' | 'other' ; modified_at : ColumnType < Date , never , never > ; } interface Pet { id : Generated < string > ; name : string ; owner_id : number ; species : 'dog' | 'cat' ; } interface Movie { id : Generated < string > ; stars : number ; } interface Database { person : Person ; pet : Pet ; movie : Movie ; 'some_schema.movie' : Movie ; } async function testFromSingle ( db ) { const [ r1 ] = await db . selectFrom ( 'person' ) . selectAll ( ) . execute ( ) ; expectType < { id : number ; first_name : string ; last_name : string | null ; age : number ; gender : 'male' | 'female' | 'other' ; modified_at : Date ; } > ( r1 ) ; const [ r2 ] = await db . selectFrom ( 'pet as p' ) . select ( 'p.species' ) . execute ( ) ; expectType < { species : 'dog' | 'cat' ; } > ( r2 ) ; const [ r3 ] = await db . selectFrom ( db . selectFrom ( 'movie' ) . select ( 'movie.stars as strs' ) . as ( 'm' ) ) . selectAll ( ) . execute ( ) ; expectType < { strs : number ; } > ( r3 ) ; const [ r4 ] = await db . selectFrom ( ( eb ) => eb . selectFrom ( 'movie' ) . select ( 'movie.stars as strs' ) . as ( 'm' ) ) . selectAll ( ) . execute ( ) ; expectType < { strs : number ; } > ( r4 ) ; const [ r5 ] = await db . selectFrom ( 'some_schema.movie' ) . select ( 'stars' ) . execute ( ) ; expectType < { stars : number ; } > ( r5 ) ; const [ r6 ] = await db . selectFrom ( 'some_schema.movie as m' ) . select ( 'm.stars' ) . execute ( ) ; expectType < { stars : number ; } > ( r6 ) ; const [ r7 ] = await db . selectFrom ( db . raw < { one : 1 ; } > ( '(select 1 as one)' ) . as ( 'o' ) ) . select ( 'o.one' ) . execute ( ) ; expectType < { one : 1 ; } > ( r7 ) ; const [ r8 ] = await db . selectFrom ( ( ) => db . raw < { one : 1 ; } > ( '(select 1 as one)' ) . as ( 'o' ) ) . select ( 'o.one' ) . execute ( ) ; expectType < { one : 1 ; } > ( r8 ) ; const [ r9 ] = await db . selectFrom ( ( eb ) => eb . selectFrom ( ( eb2 ) => eb2 . selectFrom ( ( eb3 ) => eb3 . selectFrom ( 'movie' ) . select ( 'stars as s' ) . as ( 'm1' ) ) . select ( 'm1.s as s2' ) . as ( 'm2' ) ) . select ( 'm2.s2 as s3' ) . as ( 'm3' ) ) . selectAll ( 'm3' ) . execute ( ) ; expectType < { s3 : number ; } > ( r9 ) ; expectError ( db . selectFrom ( 'person' ) . select ( 'pet.id' ) ) ; expectError ( db . selectFrom ( 'doesnt_exists' ) ) ; expectError ( db . selectFrom ( 'doesnt_exists as de' ) ) ; } async function testFromMultiple ( db ) { const [ r1 ] = await db . selectFrom ( [ 'person' , 'pet as a' , db . selectFrom ( 'movie' ) . select ( 'movie.id as movie_id' ) . as ( 'm' ) , ] ) . select ( [ 'person.first_name' , 'm.movie_id' , 'a.species' ] ) . execute ( ) ; expectType < { first_name : string ; movie_id : string ; species : 'dog' | 'cat' ; } > ( r1 ) ; expectError ( db . selectFrom ( [ 'person' , 'movie' ] ) . select ( 'pet.id' ) ) ; expectError ( db . selectFrom ( [ 'person' , 'doesnt_exists' ] ) ) ; } async function testSelectSingle ( db ) { const qb = db . selectFrom ( 'person' ) ; const [ r1 ] = await qb . select ( 'id' ) . execute ( ) ; expectType < { id : number ; } > ( r1 ) ; const [ r2 ] = await qb . select ( 'person.gender' ) . execute ( ) ; expectType < { gender : 'male' | 'female' | 'other' ; } > ( r2 ) ; const [ r3 ] = await qb . select ( 'person.age as a' ) . execute ( ) ; expectType < { a : number ; } > ( r3 ) ; const [ r4 ] = await qb . select ( db . raw < boolean > ( 'random() > 0.5' ) . as ( 'rando' ) ) . execute ( ) ; expectType < { rando : boolean ; } > ( r4 ) ; const alias = 'col_' + Math . round ( Math . random ( ) * 1000 ) ; const [ r5 ] = await qb . select ( db . raw ( 'random() > 0.5' ) . as ( alias ) ) . select ( 'first_name' ) . execute ( ) ; expectType < { first_name : string ; } & { [ key ] : unknown ; } > ( r5 ) ; const [ r6 ] = await qb . select ( db . selectFrom ( 'movie' ) . select ( 'id' ) . as ( 'movie_id' ) ) . execute ( ) ; expectType < { movie_id : string ; } > ( r6 ) ; const [ r7 ] = await qb . select ( ( qb ) => qb . selectFrom ( 'movie' ) . whereRef ( 'movie.id' , '=' , 'person.id' ) . select ( 'movie.id' ) . as ( 'movie_id' ) ) . execute ( ) ; expectType < { movie_id : string ; } > ( r7 ) ; const [ r8 ] = await db . selectFrom ( 'pet as p' ) . select ( 'p.name' ) . execute ( ) ; expectType < { name : string ; } > ( r8 ) ; const [ r9 ] = await db . selectFrom ( 'some_schema.movie' ) . select ( 'some_schema.movie.id' ) . execute ( ) ; expectType < { id : string ; } > ( r9 ) ; const [ r10 ] = await db . selectFrom ( 'some_schema.movie as sm' ) . select ( 'sm.id as identifier' ) . execute ( ) ; expectType < { identifier : string ; } > ( r10 ) ; const [ r11 ] = await qb . select ( 'id as identifier' ) . execute ( ) ; expectType < { identifier : number ; } > ( r11 ) ; const [ r12 ] = await qb . select ( db . fn . max ( 'first_name' ) . as ( 'max_first_name' ) ) . execute ( ) ; expectType < { max_first_name : string ; } > ( r12 ) ; const [ r13 ] = await qb . select ( ( qb ) => qb . fn . max ( 'first_name' ) . as ( 'max_first_name' ) ) . execute ( ) ; expectType < { max_first_name : string ; } > ( r13 ) ; const { count } = db . fn ; const r14 = await qb . select ( count < number > ( 'id' ) . as ( 'count' ) ) . executeTakeFirstOrThrow ( ) ; expectType < { count : number ; } > ( r14 ) ; expectError ( qb . select ( 'not_property' ) ) ; expectError ( qb . select ( 'person.not_property' ) ) ; expectError ( qb . select ( 'person.not_property as np' ) ) ; } async function testSelectMultiple ( db ) { const qb = db . selectFrom ( [ 'person' , ( qb ) => qb . selectFrom ( 'movie' ) . select ( [ 'movie.stars' , 'movie.id as movie_id' ] ) . as ( 'm' ) , ] ) . innerJoin ( 'pet as p' , 'id' , 'id' ) ; const [ r1 ] = await qb . select ( [ 'first_name' , 'person.age' , 'species as sp' , 'p.name as pet_name' , 'm.stars' , 'movie_id' , db . raw < number > ( 'random()' ) . as ( 'rand1' ) , db . raw < number > ( 'random()' ) . as ( 'rand2' ) , ( qb ) => qb . selectFrom ( 'pet' ) . select ( 'pet.id' ) . as ( 'sub' ) , ] ) . execute ( ) ; expectType < { first_name : string ; age : number ; sp : 'dog' | 'cat' ; pet_name : string ; stars : number ; movie_id : string ; rand1 : number ; rand2 : number ; sub : string ; } > ( r1 ) ; expectError ( qb . select ( [ 'person.id' , 'notColumn' ] ) ) ; expectError ( qb . select ( [ 'person.id' , 'person.notColumn' ] ) ) ; expectError ( qb . select ( [ 'person.id' , 'person.notColumn as foo' ] ) ) ; } async function testSelectDynamic ( db ) { const dynamicColumn = Math . random ( ) . toString ( ) ; const [ r1 ] = await db . selectFrom ( 'person' ) . select ( db . dynamic . ref ( dynamicColumn ) ) . execute ( ) ; expectType < { } > ( r1 ) ; const [ r2 ] = await db . selectFrom ( 'person' ) . select ( db . dynamic . ref < 'first_name' | 'age' > ( dynamicColumn ) ) . execute ( ) ; expectType < { first_name : string | undefined ; age : number | undefined ; } > ( r2 ) ; const [ r3 ] = await db . selectFrom ( 'person' ) . select ( [ 'last_name' , db . dynamic . ref ( dynamicColumn ) ] ) . execute ( ) ; expectType < { last_name : string | null ; } > ( r3 ) ; const [ r4 ] = await db . selectFrom ( [ 'person' , 'pet' ] ) . select ( [ 'last_name' , db . dynamic . ref < 'first_name' | 'person.age' > ( dynamicColumn ) , db . dynamic . ref < 'pet.name' | 'doesnt_exist' > ( dynamicColumn ) , ] ) . execute ( ) ; expectType < { last_name : string | null ; first_name : string | undefined ; age : number | undefined ; name : string | undefined ; doesnt_exist : never | undefined ; } > ( r4 ) ; } function testWhere ( db ) { db . selectFrom ( 'person' ) . where ( 'first_name' , '=' , 'Arnold' ) ; db . selectFrom ( 'person' ) . where ( 'person.age' , '=' , 25 ) ; db . selectFrom ( 'some_schema.movie' ) . where ( 'some_schema.movie.id' , '=' , '1' ) ; db . selectFrom ( 'movie' ) . where ( ( qb ) => qb . selectFrom ( 'person' ) . select ( 'gender' ) , '=' , 'female' ) ; db . selectFrom ( 'movie' ) . where ( db . raw ( '?' , [ 'female' ] ) , '=' , ( qb ) => qb . selectFrom ( 'person' ) . select ( 'gender' ) ) ; db . selectFrom ( 'person' ) . where ( db . raw ( 'whatever' ) , '=' , 1 ) ; db . selectFrom ( 'person' ) . where ( db . raw ( 'whatever' ) , '=' , true ) ; db . selectFrom ( 'person' ) . where ( db . raw ( 'whatever' ) , '=' , '1' ) ; db . selectFrom ( 'person' ) . where ( 'gender' , 'in' , [ 'female' , 'male' ] ) ; db . selectFrom ( 'person' ) . where ( 'person.age' , db . raw ( 'lol' ) , 25 ) ; expectError ( db . selectFrom ( 'person' ) . where ( 'person.age' , 'lol' , 25 ) ) ; expectError ( db . selectFrom ( 'person' ) . where ( 'movie.stars' , '=' , 25 ) ) ; expectError ( db . selectFrom ( 'person' ) . where ( 'stars' , '=' , 25 ) ) ; expectError ( db . selectFrom ( 'person' ) . where ( 'age' , '=' , '25' ) ) ; expectError ( db . selectFrom ( 'person' ) . where ( 'gender' , '=' , 'not_a_gender' ) ) ; expectError ( db . selectFrom ( 'person' ) . where ( 'gender' , 'in' , [ 'female' , 'not_a_gender' ] ) ) ; expectError ( db . selectFrom ( 'some_schema.movie' ) . where ( 'some_schema.movie.id' , '=' , 1 ) ) ; expectError ( db . selectFrom ( 'some_schema.movie' ) . where ( ( qb ) => qb . selectFrom ( 'person' ) . select ( 'gender' ) , '=' , 'not_a_gender' ) ) ; } async function testConditionalJoinWhere ( db ) { let qb = db . selectFrom ( 'person' ) ; let petName = 'catto' ; let petSpecies = 'cat' ; if ( petName || petSpecies ) { let qb2 = qb . innerJoin ( 'pet' , 'person.id' , 'pet.owner_id' ) ; if ( petName ) { qb2 = qb2 . where ( 'pet.name' , '=' , petName ) ; } if ( petSpecies ) { qb2 = qb2 . where ( 'pet.species' , '=' , petSpecies ) ; } qb = qb2 ; } const res = await qb . selectAll ( 'person' ) . execute ( ) ; } async function testJoin ( db ) { const r1 = await db . selectFrom ( 'person' ) . innerJoin ( 'pet' , 'pet.owner_id' , 'person.id' ) . selectAll ( ) . execute ( ) ; expectType < { id : number | string ; first_name : string ; last_name : string | null ; age : number ; gender : 'male' | 'female' | 'other' ; modified_at : Date ; name : string ; species : 'cat' | 'dog' ; owner_id : number ; } [ ] > ( r1 ) ; const r2 = await db . selectFrom ( 'person' ) . innerJoin ( 'pet as p' , ( join ) => join . onRef ( 'p.owner_id' , '=' , 'person.id' ) ) . where ( 'p.species' , 'in' , [ 'cat' ] ) . selectAll ( 'p' ) . execute ( ) ; expectType < Selectable < Pet > [ ] > ( r2 ) ; expectType < { id : string ; name : string ; species : 'cat' | 'dog' ; owner_id : number ; } [ ] > ( r2 ) ; const r3 = await db . selectFrom ( 'person' ) . innerJoin ( db . selectFrom ( 'pet' ) . select ( [ 'pet.id' , 'pet.owner_id as owner' ] ) . as ( 'p' ) , 'p.owner' , 'person.id' ) . where ( 'p.owner' , '>' , 2 ) . selectAll ( 'p' ) . execute ( ) ; expectType < { id : string ; owner : number ; } [ ] > ( r3 ) ; const r4 = await db . selectFrom ( 'person' ) . innerJoin ( ( qb ) => qb . selectFrom ( 'pet' ) . selectAll ( 'pet' ) . as ( 'p' ) , ( join ) => join . onRef ( 'p.owner_id' , '=' , 'person.id' ) ) . where ( 'p.owner_id' , '>' , 2 ) . selectAll ( 'p' ) . execute ( ) ; expectType < Selectable < Pet > [ ] > ( r4 ) ; const r5 = await db . selectFrom ( 'person' ) . leftJoin ( 'pet' , 'pet.owner_id' , 'person.id' ) . leftJoin ( 'movie' , 'movie.id' , 'person.id' ) . selectAll ( ) . executeTakeFirstOrThrow ( ) ; expectType < { id : number | string | null ; first_name : string ; last_name : string | null ; age : number ; gender : 'male' | 'female' | 'other' ; modified_at : Date ; name : string | null ; species : 'dog' | 'cat' | null ; owner_id : number | null ; stars : number | null ; } > ( r5 ) ; const r6 = await db . selectFrom ( 'person' ) . rightJoin ( 'pet' , 'pet.owner_id' , 'person.id' ) . rightJoin ( 'movie' , 'movie.id' , 'person.id' ) . selectAll ( ) . executeTakeFirstOrThrow ( ) ; expectType < { id : number | string | null ; first_name : string | null ; last_name : string | null ; age : number | null ; gender : 'male' | 'female' | 'other' | null ; modified_at : Date | null ; name : string | null ; species : 'dog' | 'cat' | null ; owner_id : number | null ; stars : number ; } > ( r6 ) ; const r7 = await db . selectFrom ( 'person' ) . fullJoin ( 'pet' , 'pet.owner_id' , 'person.id' ) . fullJoin ( 'movie' , 'movie.id' , 'person.id' ) . selectAll ( ) . executeTakeFirstOrThrow ( ) ; expectType < { id : number | string | null ; first_name : string | null ; last_name : string | null ; age : number | null ; gender : 'male' | 'female' | 'other' | null ; modified_at : Date | null ; name : string | null ; species : 'dog' | 'cat' | null ; owner_id : number | null ; stars : number | null ; } > ( r7 ) ; expectError ( db . selectFrom ( 'person' ) . innerJoin ( 'movie as m' , ( join ) => join . onRef ( 'pet.id' , '=' , 'person.id' ) ) ) ; expectError ( db . selectFrom ( 'person' ) . innerJoin ( 'movie as m' , ( join ) => join . onRef ( 'movie.id' , '=' , 'person.id' ) ) ) ; } async function testInsert ( db ) { const person = { first_name : 'Jennifer' , last_name : 'Aniston' , gender : 'other' as const , age : 30 , } ; const r1 = await db . insertInto ( 'person' ) . values ( person ) . execute ( ) ; expectType < InsertResult [ ] > ( r1 ) ; const r2 = await db . insertInto ( 'person' ) . values ( { first_name : 'fname' , age : 10 , gender : 'other' } ) . executeTakeFirst ( ) ; expectType < InsertResult > ( r2 ) ; const r3 = await db . insertInto ( 'person' ) . values ( person ) . executeTakeFirstOrThrow ( ) ; expectType < InsertResult > ( r3 ) ; const r4 = await db . with ( 'foo' , ( db ) => db . selectFrom ( 'person' ) . select ( 'id' ) . where ( 'person.id' , '=' , 1 ) ) . insertInto ( 'movie' ) . values ( { stars : ( eb ) => eb . selectFrom ( 'foo' ) . select ( 'foo.id' ) , } ) . executeTakeFirst ( ) ; expectType < InsertResult > ( r4 ) ; const r5 = await db . insertInto ( 'person' ) . values ( person ) . onConflict ( ( oc ) => oc . column ( 'id' ) . doUpdateSet ( { first_name : ( eb ) => eb . ref ( 'excluded.first_name' ) , last_name : ( eb ) => eb . ref ( 'last_name' ) , } ) ) . executeTakeFirst ( ) ; expectType < InsertResult > ( r5 ) ; expectError ( db . insertInto ( 'doesnt_exists' ) ) ; expectError ( db . insertInto ( 'person' ) . values ( { not_column : 'foo' } ) ) ; expectError ( db . insertInto ( 'person' ) . values ( { first_name : 10 , age : 10 , gender : 'other' } ) ) ; expectError ( db . insertInto ( 'person' ) . values ( { first_name : 'Jennifer' } ) ) ; expectError ( db . insertInto ( 'person' ) . values ( { modified_at : new Date ( ) } ) ) ; expectError ( db . insertInto ( 'person' ) . values ( person ) . onConflict ( ( oc ) => oc . column ( 'id' ) . doUpdateSet ( { first_name : ( eb ) => eb . ref ( 'doesnt_exist' ) , } ) ) ) ; } async function testReturning ( db ) { const person = { first_name : 'Jennifer' , last_name : 'Aniston' , gender : 'other' as const , age : 30 , } ; const r1 = await db . insertInto ( 'person' ) . values ( person ) . returning ( 'id' ) . executeTakeFirst ( ) ; expectType < { id : number ; } | undefined > ( r1 ) ; const r2 = await db . insertInto ( 'person' ) . values ( person ) . returning ( [ 'id' , 'person.first_name as fn' ] ) . execute ( ) ; expectType < { id : number ; fn : string ; } [ ] > ( r2 ) ; const r3 = await db . insertInto ( 'person' ) . values ( person ) . returning ( [ 'id' , db . raw < string > ( `concat(first_name, ' ', last_name)` ) . as ( 'full_name' ) , ( qb ) => qb . selectFrom ( 'pet' ) . select ( 'pet.id' ) . as ( 'sub' ) , ] ) . execute ( ) ; expectType < { id : number ; full_name : string ; sub : string ; } [ ] > ( r3 ) ; const r4 = await db . insertInto ( 'movie' ) . values ( { stars : 5 } ) . returningAll ( ) . executeTakeFirstOrThrow ( ) ; expectType < { id : string ; stars : number ; } > ( r4 ) ; expectError ( db . insertInto ( 'person' ) . values ( person ) . returning ( 'not_column' ) ) ; } async function testUpdate ( db ) { const r1 = await db . updateTable ( 'pet as p' ) . where ( 'p.id' , '=' , '1' ) . set ( { name : 'Fluffy' } ) . executeTakeFirst ( ) ; expectType < UpdateResult > ( r1 ) ; expectError ( db . updateTable ( 'pet as p' ) . where ( 'p.id' , '=' , '1' ) . set ( { not_a_column : 'Fluffy' } ) ) ; } async function testDelete ( db ) { const r1 = await db . deleteFrom ( 'pet' ) . where ( 'id' , '=' , '1' ) . executeTakeFirst ( ) ; expectType < DeleteResult > ( r1 ) ; } async function testOrderBy ( db ) { const r1 = await db . selectFrom ( 'person' ) . select ( [ 'id' , 'person.first_name as fn' ] ) . orderBy ( 'first_name' , 'desc' ) . orderBy ( 'fn' ) . execute ( ) ; } async function testKyselyAndTransactionTypes ( db ) { let trx = { } as unknown as Transaction < Database > ; expectError ( ( trx = db ) ) ; db = trx ; } async function testWith ( db ) { const r1 = await db . with ( 'jennifers' , ( db ) => db . selectFrom ( 'person' ) . where ( 'first_name' , '=' , 'Jennifer' ) . selectAll ( ) ) . with ( 'female_jennifers' , ( db ) => db . selectFrom ( 'jennifers' ) . select ( 'first_name' ) . where ( 'gender' , '=' , 'female' ) . selectAll ( 'jennifers' ) . select ( [ 'first_name as fn' , 'last_name as ln' ] ) ) . selectFrom ( 'female_jennifers' ) . select ( [ 'fn' , 'ln' ] ) . execute ( ) ; expectType < { fn : string ; ln : string | null ; } [ ] > ( r1 ) ; const r2 = await db . with ( 'jennifers(first_name, ln, gender)' , ( db ) => db . selectFrom ( 'person' ) . where ( 'first_name' , '=' , 'Jennifer' ) . select ( [ 'first_name' , 'last_name as ln' , 'gender' ] ) ) . selectFrom ( 'jennifers' ) . select ( [ 'first_name' , 'ln' ] ) . execute ( ) ; expectType < { first_name : string ; ln : string | null ; } [ ] > ( r2 ) ; const r3 = await db . withRecursive ( 'jennifers(first_name, ln)' , ( db ) => db . selectFrom ( 'person' ) . where ( 'first_name' , '=' , 'Jennifer' ) . select ( [ 'first_name' , 'last_name as ln' ] ) . union ( db . selectFrom ( 'jennifers' ) . select ( [ 'first_name' , 'ln' ] ) ) ) . selectFrom ( 'jennifers' ) . select ( [ 'first_name' , 'ln' ] ) . execute ( ) ; expectType < { first_name : string ; ln : string | null ; } [ ] > ( r3 ) ; expectError ( db . with ( 'jennifers(first_name, last_name, gender)' , ( db ) => db . selectFrom ( 'person' ) . where ( 'first_name' , '=' , 'Jennifer' ) . select ( [ 'first_name' , 'last_name' ] ) ) . selectFrom ( 'jennifers' ) . select ( [ 'first_name' , 'last_name' ] ) ) ; } async function testExecuteTakeFirstOrThrow ( db ) { const r1 = await db . selectFrom ( 'person' ) . selectAll ( ) . where ( 'id' , '=' , 1 ) . executeTakeFirstOrThrow ( ) ; expectType < Selectable < Person > > ( r1 ) ; } async function testUnion ( db ) { const r1 = await db . selectFrom ( 'person' ) . select ( [ 'id' , 'first_name as name' ] ) . where ( 'id' , 'in' , [ 1 , 2 , 3 ] ) . union ( db . selectFrom ( 'pet' ) . select ( 'name' ) . select ( 'owner_id as id' ) ) . executeTakeFirstOrThrow ( ) ; expectType < { id : number ; name : string ; } > ( r1 ) ; const r2 = await db . selectFrom ( 'person' ) . select ( [ 'id' , 'first_name as name' ] ) . where ( 'id' , 'in' , [ 1 , 2 , 3 ] ) . union ( db . raw < { id : number ; name : string ; } > ( "(1, 'Sami')" ) ) . executeTakeFirstOrThrow ( ) ; expectType < { id : number ; name : string ; } > ( r2 ) ; expectError ( db . selectFrom ( 'person' ) . select ( [ 'id' , 'first_name as name' ] ) . where ( 'id' , 'in' , [ 1 , 2 , 3 ] ) . union ( db . selectFrom ( 'pet' ) . select ( 'name' ) . select ( 'owner_id' ) ) ) ; } async function testCall ( db ) { const [ r1 ] = await db . selectFrom ( 'pet as p' ) . select ( 'p.species' ) . call ( ( qb ) => qb . select ( 'name' ) ) . execute ( ) ; expectType < { species : 'dog' | 'cat' ; } & { name : string ; } > ( r1 ) ; } async function testGenericSelect < T extends keyof Database > ( db , table ) { const r1 = await db . selectFrom ( table ) . select ( 'id' ) . executeTakeFirstOrThrow ( ) ; expectAssignable < string | number > ( r1 . id ) ; } async function testGenericUpdate ( db , table ) { await db . updateTable ( table ) . set ( { id : '123' } ) . execute ( ) ; }