@@ -692,6 +692,179 @@ describe(`QueryCollection`, () => {
692692 ) as MetaDataType < TestItem >
693693 expect ( initialCache ) . toEqual ( initialMetaData )
694694 } )
695+
696+ it ( `should not throw error when using writeInsert with select option` , async ( ) => {
697+ const queryKey = [ `select-writeInsert-test` ]
698+ const consoleErrorSpy = vi
699+ . spyOn ( console , `error` )
700+ . mockImplementation ( ( ) => { } )
701+
702+ const queryFn = vi . fn ( ) . mockResolvedValue ( initialMetaData )
703+ const select = vi . fn ( ( data : MetaDataType < TestItem > ) => data . data )
704+
705+ const options = queryCollectionOptions ( {
706+ id : `select-writeInsert-test` ,
707+ queryClient,
708+ queryKey,
709+ queryFn,
710+ select,
711+ getKey,
712+ startSync : true ,
713+ } )
714+ const collection = createCollection ( options )
715+
716+ // Wait for collection to be ready
717+ await vi . waitFor ( ( ) => {
718+ expect ( collection . status ) . toBe ( `ready` )
719+ expect ( collection . size ) . toBe ( 2 )
720+ } )
721+
722+ // This should NOT cause an error - but with the bug it does
723+ const newItem : TestItem = { id : `3` , name : `New Item` }
724+ collection . utils . writeInsert ( newItem )
725+
726+ // Verify the item was inserted
727+ expect ( collection . size ) . toBe ( 3 )
728+ expect ( collection . get ( `3` ) ) . toEqual ( newItem )
729+
730+ // Wait a tick to allow any async error handlers to run
731+ await flushPromises ( )
732+
733+ // Verify no error was logged about select returning non-array
734+ const errorCallArgs = consoleErrorSpy . mock . calls . find ( ( call ) =>
735+ call [ 0 ] ?. includes ?.(
736+ `@tanstack/query-db-collection: select() must return an array of objects` ,
737+ ) ,
738+ )
739+ expect ( errorCallArgs ) . toBeUndefined ( )
740+
741+ consoleErrorSpy . mockRestore ( )
742+ } )
743+
744+ it ( `should not throw error when using writeUpsert with select option` , async ( ) => {
745+ const queryKey = [ `select-writeUpsert-test` ]
746+ const consoleErrorSpy = vi
747+ . spyOn ( console , `error` )
748+ . mockImplementation ( ( ) => { } )
749+
750+ const queryFn = vi . fn ( ) . mockResolvedValue ( initialMetaData )
751+ const select = vi . fn ( ( data : MetaDataType < TestItem > ) => data . data )
752+
753+ const options = queryCollectionOptions ( {
754+ id : `select-writeUpsert-test` ,
755+ queryClient,
756+ queryKey,
757+ queryFn,
758+ select,
759+ getKey,
760+ startSync : true ,
761+ } )
762+ const collection = createCollection ( options )
763+
764+ // Wait for collection to be ready
765+ await vi . waitFor ( ( ) => {
766+ expect ( collection . status ) . toBe ( `ready` )
767+ expect ( collection . size ) . toBe ( 2 )
768+ } )
769+
770+ // This should NOT cause an error - but with the bug it does
771+ // Test upsert for new item
772+ const newItem : TestItem = { id : `3` , name : `Upserted New Item` }
773+ collection . utils . writeUpsert ( newItem )
774+
775+ // Verify the item was inserted
776+ expect ( collection . size ) . toBe ( 3 )
777+ expect ( collection . get ( `3` ) ) . toEqual ( newItem )
778+
779+ // Test upsert for existing item
780+ collection . utils . writeUpsert ( { id : `1` , name : `Updated First Item` } )
781+
782+ // Verify the item was updated
783+ expect ( collection . get ( `1` ) ?. name ) . toBe ( `Updated First Item` )
784+
785+ // Wait a tick to allow any async error handlers to run
786+ await flushPromises ( )
787+
788+ // Verify no error was logged about select returning non-array
789+ const errorCallArgs = consoleErrorSpy . mock . calls . find ( ( call ) =>
790+ call [ 0 ] ?. includes ?.(
791+ `@tanstack/query-db-collection: select() must return an array of objects` ,
792+ ) ,
793+ )
794+ expect ( errorCallArgs ) . toBeUndefined ( )
795+
796+ consoleErrorSpy . mockRestore ( )
797+ } )
798+
799+ it ( `should update query cache with wrapped format preserved when using writeInsert with select option` , async ( ) => {
800+ const queryKey = [ `select-cache-update-test` ]
801+
802+ const queryFn = vi . fn ( ) . mockResolvedValue ( initialMetaData )
803+ const select = vi . fn ( ( data : MetaDataType < TestItem > ) => data . data )
804+
805+ const options = queryCollectionOptions ( {
806+ id : `select-cache-update-test` ,
807+ queryClient,
808+ queryKey,
809+ queryFn,
810+ select,
811+ getKey,
812+ startSync : true ,
813+ } )
814+ const collection = createCollection ( options )
815+
816+ // Wait for collection to be ready
817+ await vi . waitFor ( ( ) => {
818+ expect ( collection . status ) . toBe ( `ready` )
819+ expect ( collection . size ) . toBe ( 2 )
820+ } )
821+
822+ // Verify initial cache has wrapped format
823+ const initialCache = queryClient . getQueryData (
824+ queryKey ,
825+ ) as MetaDataType < TestItem >
826+ expect ( initialCache . metaDataOne ) . toBe ( `example metadata` )
827+ expect ( initialCache . metaDataTwo ) . toBe ( `example metadata` )
828+ expect ( initialCache . data ) . toHaveLength ( 2 )
829+
830+ // Insert a new item
831+ const newItem : TestItem = { id : `3` , name : `New Item` }
832+ collection . utils . writeInsert ( newItem )
833+
834+ // Verify the cache still has wrapped format with metadata preserved
835+ const cacheAfterInsert = queryClient . getQueryData (
836+ queryKey ,
837+ ) as MetaDataType < TestItem >
838+ expect ( cacheAfterInsert . metaDataOne ) . toBe ( `example metadata` )
839+ expect ( cacheAfterInsert . metaDataTwo ) . toBe ( `example metadata` )
840+ expect ( cacheAfterInsert . data ) . toHaveLength ( 3 )
841+ expect ( cacheAfterInsert . data ) . toContainEqual ( newItem )
842+
843+ // Update an existing item
844+ collection . utils . writeUpdate ( { id : `1` , name : `Updated First Item` } )
845+
846+ // Verify the cache still has wrapped format
847+ const cacheAfterUpdate = queryClient . getQueryData (
848+ queryKey ,
849+ ) as MetaDataType < TestItem >
850+ expect ( cacheAfterUpdate . metaDataOne ) . toBe ( `example metadata` )
851+ expect ( cacheAfterUpdate . data ) . toHaveLength ( 3 )
852+ const updatedItem = cacheAfterUpdate . data . find ( ( item ) => item . id === `1` )
853+ expect ( updatedItem ?. name ) . toBe ( `Updated First Item` )
854+
855+ // Delete an item
856+ collection . utils . writeDelete ( `2` )
857+
858+ // Verify the cache still has wrapped format
859+ const cacheAfterDelete = queryClient . getQueryData (
860+ queryKey ,
861+ ) as MetaDataType < TestItem >
862+ expect ( cacheAfterDelete . metaDataOne ) . toBe ( `example metadata` )
863+ expect ( cacheAfterDelete . data ) . toHaveLength ( 2 )
864+ expect ( cacheAfterDelete . data ) . not . toContainEqual (
865+ expect . objectContaining ( { id : `2` } ) ,
866+ )
867+ } )
695868 } )
696869 describe ( `Direct persistence handlers` , ( ) => {
697870 it ( `should pass through direct persistence handlers to collection options` , ( ) => {
0 commit comments