@@ -32,6 +32,10 @@ const schema = defineSchema({
3232 lastName : v . string ( ) ,
3333 fullName : v . string ( ) ,
3434 } ) ,
35+
36+ userCount : defineTable ( {
37+ count : v . number ( ) ,
38+ } ) ,
3539} ) ;
3640type DataModel = DataModelFromSchemaDefinition < typeof schema > ;
3741const rawMutation = mutationGeneric as MutationBuilder < DataModel , "public" > ;
@@ -70,6 +74,20 @@ triggers.register("usersExplicitIncorrectTable", async (ctx, change) => {
7074 }
7175} ) ;
7276
77+ // Keep a denormalized count of all users.
78+ triggers . register ( "usersExplicit" , async ( ctx , change ) => {
79+ const countDoc = await ctx . db . query ( "userCount" ) . first ( ) ;
80+ const currentCount = countDoc ?. count ?? 0 ;
81+ const countId =
82+ countDoc ?. _id ?? ( await ctx . db . insert ( "userCount" , { count : 0 } ) ) ;
83+
84+ if ( change . operation === "insert" ) {
85+ await ctx . db . patch ( "userCount" , countId , { count : currentCount + 1 } ) ;
86+ } else if ( change . operation === "delete" ) {
87+ await ctx . db . patch ( "userCount" , countId , { count : currentCount - 1 } ) ;
88+ }
89+ } ) ;
90+
7391const mutation = customMutation ( rawMutation , customCtx ( triggers . wrapDB ) ) ;
7492
7593export const createUser = mutation ( {
@@ -105,11 +123,30 @@ export const createUserExplicitIncorrectTable = mutation({
105123 } ,
106124} ) ;
107125
126+ export const updateUser = mutation ( {
127+ args : {
128+ id : v . id ( "usersExplicit" ) ,
129+ firstName : v . string ( ) ,
130+ } ,
131+ handler : async ( ctx , { id, firstName } ) => {
132+ return ctx . db . patch ( "usersExplicit" , id , { firstName } ) ;
133+ } ,
134+ } ) ;
135+
136+ export const deleteUser = mutation ( {
137+ args : { id : v . id ( "usersExplicit" ) } ,
138+ handler : async ( ctx , args ) => {
139+ return ctx . db . delete ( "usersExplicit" , args . id ) ;
140+ } ,
141+ } ) ;
142+
108143const testApi : ApiFromModules < {
109144 fns : {
110145 createUser : typeof createUser ;
111146 createUserExplicit : typeof createUserExplicit ;
112147 createUserExplicitIncorrectTable : typeof createUserExplicitIncorrectTable ;
148+ updateUser : typeof updateUser ;
149+ deleteUser : typeof deleteUser ;
113150 } ;
114151} > [ "fns" ] = anyApi [ "triggers.test" ] as any ;
115152
@@ -148,3 +185,40 @@ test("trigger with wrong usage of explicit IDs fails", async () => {
148185 "Invalid argument `id`, expected ID in table 'users' but got ID in table 'usersExplicitIncorrectTable'" ,
149186 ) ;
150187} ) ;
188+
189+ test ( "create, update and delete" , async ( ) => {
190+ const t = convexTest ( schema , modules ) ;
191+
192+ async function getUserCount ( ) {
193+ return await t . run ( async ( ctx ) => {
194+ const countDoc = await ctx . db . query ( "userCount" ) . first ( ) ;
195+ return countDoc ?. count ?? null ;
196+ } ) ;
197+ }
198+
199+ expect ( await getUserCount ( ) ) . toBeNull ( ) ;
200+
201+ const userId = await t . mutation ( testApi . createUserExplicit , {
202+ firstName : "Jane" ,
203+ lastName : "Smith" ,
204+ } ) ;
205+ expect ( await getUserCount ( ) ) . toBe ( 1 ) ;
206+
207+ const user2Id = await t . mutation ( testApi . createUserExplicit , {
208+ firstName : "Alex" ,
209+ lastName : "Johnson" ,
210+ } ) ;
211+ expect ( await getUserCount ( ) ) . toBe ( 2 ) ;
212+
213+ await t . mutation ( testApi . updateUser , {
214+ id : userId ,
215+ firstName : "Janet" ,
216+ } ) ;
217+ expect ( await getUserCount ( ) ) . toBe ( 2 ) ;
218+
219+ await t . mutation ( testApi . deleteUser , { id : userId } ) ;
220+ expect ( await getUserCount ( ) ) . toBe ( 1 ) ;
221+
222+ await t . mutation ( testApi . deleteUser , { id : user2Id } ) ;
223+ expect ( await getUserCount ( ) ) . toBe ( 0 ) ;
224+ } ) ;
0 commit comments