@@ -315,22 +315,16 @@ test("init", async () => {
315315 },
316316 "dbSchema": {
317317 "indexes": [],
318- "tables": [
319- {
320- "columns": [
321- "title",
322- "isCompleted",
323- "categoryId",
324- ],
325- "name": "todo",
318+ "tables": {
319+ "todo": Set {
320+ "title",
321+ "isCompleted",
322+ "categoryId",
326323 },
327- {
328- "columns": [
329- "name",
330- ],
331- "name": "todoCategory",
324+ "todoCategory": Set {
325+ "name",
332326 },
333- ] ,
327+ } ,
334328 },
335329 "type": "init",
336330 },
@@ -1257,3 +1251,96 @@ describe("useOwner", () => {
12571251 expect ( postMessageCalls [ 0 ] ) . toEqual ( ownerMessage ( testOwner , false ) ) ;
12581252 } ) ;
12591253} ) ;
1254+
1255+ describe ( "createQuery type inference" , ( ) => {
1256+ test ( "Query.Row infers correct types for simple selectAll" , async ( ) => {
1257+ const { evolu } = await testCreateEvolu ( ) ;
1258+
1259+ const _allTodosQuery = evolu . createQuery ( ( db ) =>
1260+ db . selectFrom ( "todo" ) . selectAll ( ) ,
1261+ ) ;
1262+
1263+ type AllTodosRow = typeof _allTodosQuery . Row ;
1264+
1265+ // Verify the Row type has the correct shape including user-defined columns
1266+ expectTypeOf < AllTodosRow > ( ) . toExtend < {
1267+ readonly id : TodoId ;
1268+ readonly title : NonEmptyString50 | null ;
1269+ readonly isCompleted : SqliteBoolean | null ;
1270+ readonly categoryId : TodoCategoryId | null ;
1271+ } > ( ) ;
1272+
1273+ // Verify system columns are included
1274+ expectTypeOf < AllTodosRow > ( ) . toHaveProperty ( "createdAt" ) ;
1275+ expectTypeOf < AllTodosRow > ( ) . toHaveProperty ( "updatedAt" ) ;
1276+ expectTypeOf < AllTodosRow > ( ) . toHaveProperty ( "isDeleted" ) ;
1277+ expectTypeOf < AllTodosRow > ( ) . toHaveProperty ( "ownerId" ) ;
1278+ } ) ;
1279+
1280+ test ( "Query.Row infers correct types for select with specific columns" , async ( ) => {
1281+ const { evolu } = await testCreateEvolu ( ) ;
1282+
1283+ const _todoTitlesQuery = evolu . createQuery ( ( db ) =>
1284+ db . selectFrom ( "todo" ) . select ( [ "id" , "title" ] ) ,
1285+ ) ;
1286+
1287+ type TodoTitlesRow = typeof _todoTitlesQuery . Row ;
1288+
1289+ // Should only have selected columns
1290+ expectTypeOf < TodoTitlesRow [ "id" ] > ( ) . toEqualTypeOf < TodoId > ( ) ;
1291+ expectTypeOf <
1292+ TodoTitlesRow [ "title" ]
1293+ > ( ) . toEqualTypeOf < NonEmptyString50 | null > ( ) ;
1294+ } ) ;
1295+
1296+ test ( "Query.Row infers correct types for table with foreign key" , async ( ) => {
1297+ const { evolu } = await testCreateEvolu ( ) ;
1298+
1299+ const _todosWithCategoryQuery = evolu . createQuery ( ( db ) =>
1300+ db . selectFrom ( "todo" ) . select ( [ "id" , "title" , "categoryId" ] ) ,
1301+ ) ;
1302+
1303+ type TodosWithCategoryRow = typeof _todosWithCategoryQuery . Row ;
1304+
1305+ expectTypeOf < TodosWithCategoryRow [ "id" ] > ( ) . toEqualTypeOf < TodoId > ( ) ;
1306+ expectTypeOf <
1307+ TodosWithCategoryRow [ "title" ]
1308+ > ( ) . toEqualTypeOf < NonEmptyString50 | null > ( ) ;
1309+ expectTypeOf <
1310+ TodosWithCategoryRow [ "categoryId" ]
1311+ > ( ) . toEqualTypeOf < TodoCategoryId | null > ( ) ;
1312+ } ) ;
1313+
1314+ test ( "Query.Row infers correct types for different table" , async ( ) => {
1315+ const { evolu } = await testCreateEvolu ( ) ;
1316+
1317+ const _categoriesQuery = evolu . createQuery ( ( db ) =>
1318+ db . selectFrom ( "todoCategory" ) . select ( [ "id" , "name" ] ) ,
1319+ ) ;
1320+
1321+ type CategoriesRow = typeof _categoriesQuery . Row ;
1322+
1323+ expectTypeOf < CategoriesRow [ "id" ] > ( ) . toEqualTypeOf < TodoCategoryId > ( ) ;
1324+ expectTypeOf <
1325+ CategoriesRow [ "name" ]
1326+ > ( ) . toEqualTypeOf < NonEmptyString50 | null > ( ) ;
1327+ } ) ;
1328+
1329+ test ( "Query.Row infers correct types with $narrowType" , async ( ) => {
1330+ const { evolu } = await testCreateEvolu ( ) ;
1331+
1332+ const _nonNullTitlesQuery = evolu . createQuery ( ( db ) =>
1333+ db
1334+ . selectFrom ( "todo" )
1335+ . select ( [ "id" , "title" ] )
1336+ . where ( "title" , "is not" , null )
1337+ . $narrowType < { title : NonEmptyString50 } > ( ) ,
1338+ ) ;
1339+
1340+ type NonNullTitlesRow = typeof _nonNullTitlesQuery . Row ;
1341+
1342+ // After $narrowType, title should not be nullable
1343+ expectTypeOf < NonNullTitlesRow [ "id" ] > ( ) . toEqualTypeOf < TodoId > ( ) ;
1344+ expectTypeOf < NonNullTitlesRow [ "title" ] > ( ) . toEqualTypeOf < NonEmptyString50 > ( ) ;
1345+ } ) ;
1346+ } ) ;
0 commit comments