11'use strict'
22
3- const { promisify } = require ( 'util' )
4- const setImmediatePromise = promisify ( setImmediate )
3+ const {
4+ setTimeout,
5+ setImmediate
6+ } = require ( 'node:timers/promises' )
7+ const { promisify } = require ( 'node:util' )
8+
59const MAIN_DB_WORKER_ACTIONS = require (
610 'bfx-facs-db-better-sqlite/worker/db-worker-actions/db-worker-actions.const'
711)
@@ -30,7 +34,8 @@ const {
3034 getGroupQuery,
3135 getSubQuery,
3236 getLimitQuery,
33- manageTransaction
37+ manageTransaction,
38+ isLockedDbError
3439} = require ( './helpers' )
3540
3641const {
@@ -87,6 +92,10 @@ class BetterSqliteDAO extends DAO {
8792
8893 this . _querySet = new Set ( )
8994 this . _transQuerySet = new Set ( )
95+
96+ this . _lockedDbRetryTimeout = 300
97+ this . _lockedDbRetryAmount = 0
98+ this . _lockedDbRetryInTrxAmount = 0
9099 }
91100
92101 async restartDb ( opts = { } ) {
@@ -136,6 +145,19 @@ class BetterSqliteDAO extends DAO {
136145 } catch ( err ) {
137146 this . _querySet . delete ( newQueryPromise )
138147
148+ if (
149+ isLockedDbError ( err ) &&
150+ this . _lockedDbRetryAmount < 3
151+ ) {
152+ await setTimeout ( this . _lockedDbRetryTimeout )
153+
154+ this . _lockedDbRetryAmount += 1
155+ const res = await this . query ( args , opts )
156+ this . _lockedDbRetryAmount = 0
157+
158+ return res
159+ }
160+
139161 throw err
140162 }
141163 }
@@ -170,18 +192,34 @@ class BetterSqliteDAO extends DAO {
170192
171193 return res
172194 } catch ( err ) {
173- // Transaction was forcefully rolled back
174- if ( ! this . db . inTransaction ) {
175- throw err
176- }
177- if ( isTransBegun ) {
195+ // if this.db.inTransaction, trx was forcefully rolled back
196+ if (
197+ this . db . inTransaction &&
198+ isTransBegun
199+ ) {
178200 this . db . prepare ( 'ROLLBACK' ) . run ( )
179201 isTransBegun = false
180202 }
181- if ( typeof afterTransFn === 'function' ) {
203+ if (
204+ this . db . inTransaction &&
205+ typeof afterTransFn === 'function'
206+ ) {
182207 await afterTransFn ( )
183208 }
184209
210+ if (
211+ isLockedDbError ( err ) &&
212+ this . _lockedDbRetryInTrxAmount < 3
213+ ) {
214+ await setTimeout ( this . _lockedDbRetryTimeout )
215+
216+ this . _lockedDbRetryInTrxAmount += 1
217+ const res = await this . _proccesTrans ( asyncExecQuery , opts )
218+ this . _lockedDbRetryInTrxAmount = 0
219+
220+ return res
221+ }
222+
185223 throw err
186224 }
187225 }
@@ -559,7 +597,7 @@ class BetterSqliteDAO extends DAO {
559597 let endId = firstId + chunkLength - 1
560598
561599 while ( true ) {
562- await setImmediatePromise ( )
600+ await setImmediate ( )
563601
564602 if (
565603 ! Number . isFinite ( startId ) ||
@@ -859,7 +897,7 @@ class BetterSqliteDAO extends DAO {
859897 }
860898
861899 for ( const obj of data ) {
862- await setImmediatePromise ( )
900+ await setImmediate ( )
863901
864902 const _obj = mixUserIdToArrData (
865903 auth ,
@@ -894,7 +932,7 @@ class BetterSqliteDAO extends DAO {
894932
895933 await this . _beginTrans ( async ( ) => {
896934 for ( const { sql, params } of queries ) {
897- await setImmediatePromise ( )
935+ await setImmediate ( )
898936
899937 await this . query ( {
900938 action : MAIN_DB_WORKER_ACTIONS . RUN ,
@@ -1207,7 +1245,7 @@ class BetterSqliteDAO extends DAO {
12071245 const params = [ ]
12081246
12091247 for ( const obj of data ) {
1210- await setImmediatePromise ( )
1248+ await setImmediate ( )
12111249
12121250 const filter = mapObjBySchema ( obj , filterPropNames )
12131251 const newItem = mapObjBySchema ( obj , upPropNames )
@@ -1232,7 +1270,7 @@ class BetterSqliteDAO extends DAO {
12321270
12331271 await this . _beginTrans ( async ( ) => {
12341272 for ( const [ i , paramsItem ] of params . entries ( ) ) {
1235- await setImmediatePromise ( )
1273+ await setImmediate ( )
12361274
12371275 await this . query ( {
12381276 action : MAIN_DB_WORKER_ACTIONS . RUN ,
@@ -1252,9 +1290,55 @@ class BetterSqliteDAO extends DAO {
12521290 } = opts ?? { }
12531291 const data = serializeObj ( record )
12541292
1255- const res = await this . query ( {
1256- action : DB_WORKER_ACTIONS . UPDATE_RECORD_OF ,
1257- params : { data, name }
1293+ const res = await this . _beginTrans ( async ( ) => {
1294+ const elems = await this . query ( {
1295+ action : MAIN_DB_WORKER_ACTIONS . ALL ,
1296+ sql : `SELECT * FROM ${ name } `
1297+ } , { doNotQueueQuery : true } )
1298+
1299+ if (
1300+ ! Array . isArray ( elems ) ||
1301+ elems . length === 0
1302+ ) {
1303+ const keys = Object . keys ( data )
1304+ const projection = getProjectionQuery ( keys )
1305+ const {
1306+ placeholders,
1307+ placeholderVal
1308+ } = getPlaceholdersQuery ( data , keys )
1309+
1310+ return await this . query ( {
1311+ action : MAIN_DB_WORKER_ACTIONS . RUN ,
1312+ sql : `INSERT INTO ${ name } (${ projection } )
1313+ VALUES (${ placeholders } )` ,
1314+ params : placeholderVal
1315+ } , { doNotQueueQuery : true } )
1316+ }
1317+ if ( elems . length > 1 ) {
1318+ await this . query ( {
1319+ action : MAIN_DB_WORKER_ACTIONS . RUN ,
1320+ sql : `DELETE FROM ${ name } WHERE _id != $_id` ,
1321+ params : { _id : elems [ 0 ] . _id }
1322+ } , { doNotQueueQuery : true } )
1323+ }
1324+
1325+ const { _id } = elems [ 0 ] ?? { }
1326+ const values = { _id }
1327+ const fields = Object . keys ( data )
1328+ . map ( ( item ) => {
1329+ const key = `new_${ item } `
1330+ values [ key ] = data [ item ]
1331+
1332+ return `${ item } = $${ key } `
1333+ } )
1334+ . join ( ', ' )
1335+
1336+ return await this . query ( {
1337+ action : MAIN_DB_WORKER_ACTIONS . RUN ,
1338+ sql : `UPDATE ${ name } SET ${ fields }
1339+ WHERE _id = $_id` ,
1340+ params : values
1341+ } , { doNotQueueQuery : true } )
12581342 } )
12591343
12601344 if ( shouldNotThrowError ) {
0 commit comments