1
1
import * as _ from 'lodash' ;
2
- import { PickReferenceKeys , PopulatedByKeys , populateDoc , populateSnapshots } from './populate' ;
2
+ import { PickReferenceKeys , populateDoc , populateSnapshots } from './populate' ;
3
3
import { StatusError } from './utils/status-error' ;
4
- import type { StrapiQuery , StrapiContext } from './types' ;
4
+ import type { StrapiQuery , StrapiContext , TransactionSuccessHook } from './types' ;
5
5
import type { Queryable } from './db/collection' ;
6
6
import type { Transaction } from './db/transaction' ;
7
7
import type { Reference , Snapshot } from './db/reference' ;
@@ -52,20 +52,25 @@ export function queries<T extends object>({ model, strapi }: StrapiContext<T>):
52
52
? model . db . doc ( model . getPK ( values ) )
53
53
: model . db . doc ( ) ;
54
54
55
- return await model . runTransaction ( async trans => {
55
+ const { result , onSuccess } = await model . runTransaction ( async trans => {
56
56
// Create while coercing data and updating relations
57
57
const data = await trans . create ( ref , values ) ;
58
- await model . options . onChange ( undefined , data , trans ) ;
58
+ const onSuccess = await model . options . onChange ( undefined , data , trans ) ;
59
59
60
60
// Populate relations
61
- return await populateDoc ( model , ref , data , populate , trans ) ;
61
+ const result = await populateDoc ( model , ref , data , populate , trans ) ;
62
+ return { result, onSuccess } ;
62
63
} ) ;
64
+
65
+ // Run the success hook
66
+ await runOnSuccess ( onSuccess , result as any ) ;
67
+ return result ;
63
68
} ;
64
69
65
70
const update : FirestoreConnectorQueries < T > [ 'update' ] = async ( params , values , populate = ( model . defaultPopulate as any ) ) => {
66
71
log ( 'update' , { params, populate } ) ;
67
72
68
- return await model . runTransaction ( async trans => {
73
+ const { result , onSuccess } = await model . runTransaction ( async trans => {
69
74
const [ snap ] = await buildAndFetchQuery ( {
70
75
model,
71
76
params : { ...params , _limit : 1 } ,
@@ -81,17 +86,22 @@ export function queries<T extends object>({ model, strapi }: StrapiContext<T>):
81
86
...snap . data ( ) ,
82
87
...await trans . update ( snap . ref , values ) ,
83
88
} ;
84
- await model . options . onChange ( prevData , data , trans ) ;
89
+ const onSuccess = await model . options . onChange ( prevData , data , trans ) ;
85
90
86
91
// Populate relations
87
- return await populateDoc ( model , snap . ref , data , populate , trans ) ;
92
+ const result = await populateDoc ( model , snap . ref , data , populate , trans ) ;
93
+ return { result, onSuccess } ;
88
94
} ) ;
95
+
96
+ // Run the success hook
97
+ await runOnSuccess ( onSuccess , result as any ) ;
98
+ return result ;
89
99
} ;
90
100
91
101
const deleteMany : FirestoreConnectorQueries < T > [ 'delete' ] = async ( params , populate = ( model . defaultPopulate as any ) ) => {
92
102
log ( 'delete' , { params, populate } ) ;
93
103
94
- return await model . runTransaction ( async trans => {
104
+ const results = await model . runTransaction ( async trans => {
95
105
const query = buildQuery ( model . db , { model, params } ) ;
96
106
const snaps = await fetchQuery ( query , trans ) ;
97
107
@@ -105,9 +115,25 @@ export function queries<T extends object>({ model, strapi }: StrapiContext<T>):
105
115
) ;
106
116
}
107
117
} ) ;
118
+
119
+ // Run the success hook
120
+ if ( Array . isArray ( results ) ) {
121
+ await Promise . all ( results . map ( r => r && runOnSuccess ( r . onSuccess , r . result as any ) ) ) ;
122
+ } else {
123
+ if ( results ) {
124
+ await runOnSuccess ( results . onSuccess , results . result as any ) ;
125
+ }
126
+ }
127
+
128
+ // Return the results
129
+ if ( Array . isArray ( results ) ) {
130
+ return results . map ( r => r && r . result ) ;
131
+ } else {
132
+ return results && results . result ;
133
+ }
108
134
} ;
109
135
110
- async function deleteOne < K extends PickReferenceKeys < T > > ( snap : Snapshot < T > , populate : K [ ] , trans : Transaction ) : Promise < PopulatedByKeys < T , K > | null > {
136
+ async function deleteOne < K extends PickReferenceKeys < T > > ( snap : Snapshot < T > , populate : K [ ] , trans : Transaction ) {
111
137
const prevData = snap . data ( ) ;
112
138
if ( ! prevData ) {
113
139
// Delete API returns `null` rather than throwing an error for non-existent documents
@@ -116,10 +142,11 @@ export function queries<T extends object>({ model, strapi }: StrapiContext<T>):
116
142
117
143
// Delete while updating relations
118
144
await trans . delete ( snap . ref ) ;
119
- await model . options . onChange ( prevData , undefined , trans ) ;
145
+ const onSuccess = await model . options . onChange ( prevData , undefined , trans ) ;
120
146
121
147
// Populate relations
122
- return await populateDoc ( model , snap . ref , prevData , populate , trans ) ;
148
+ const result = await populateDoc ( model , snap . ref , prevData , populate , trans ) ;
149
+ return { result, onSuccess } ;
123
150
} ;
124
151
125
152
const search : FirestoreConnectorQueries < T > [ 'search' ] = async ( params , populate = ( model . defaultPopulate as any ) ) => {
@@ -213,3 +240,13 @@ async function fetchQuery<T extends object>(queryOrRefs: Queryable<T> | Referenc
213
240
return result . docs ;
214
241
}
215
242
}
243
+
244
+ async function runOnSuccess < T extends object > ( onSuccess : void | TransactionSuccessHook < T > , result : T | undefined ) {
245
+ if ( typeof onSuccess === 'function' ) {
246
+ try {
247
+ await onSuccess ( result ) ;
248
+ } catch ( err ) {
249
+ strapi . log . warn ( `Transaction onSuccess hook threw an error: ${ ( err as any ) . message } ` , err ) ;
250
+ }
251
+ }
252
+ }
0 commit comments