(dbName, op, ...args)
| 114 | } |
| 115 | |
| 116 | const dbAction = (dbName, op, ...args) => { |
| 117 | if (op === 'compactDatafile') { |
| 118 | db[dbName].persistence.compactDatafile() |
| 119 | return |
| 120 | } |
| 121 | return new Promise((resolve, reject) => { |
| 122 | if (op === 'find') { |
| 123 | db[dbName][op](...args, (err, results) => { |
| 124 | if (err) return reject(err) |
| 125 | resolve((results || []).map(doc => decryptDoc(dbName, doc))) |
| 126 | }) |
| 127 | } else if (op === 'findOne') { |
| 128 | db[dbName][op](...args, (err, result) => { |
| 129 | if (err) return reject(err) |
| 130 | resolve(decryptDoc(dbName, result)) |
| 131 | }) |
| 132 | } else if (op === 'insert') { |
| 133 | const original = args[0] |
| 134 | const toInsert = Array.isArray(original) |
| 135 | ? original.map(d => encryptDoc(dbName, d)) |
| 136 | : encryptDoc(dbName, original) |
| 137 | db[dbName][op](toInsert, (err, inserted) => { |
| 138 | if (err) { |
| 139 | // Handle unique constraint violation by falling back to update, |
| 140 | // matching SQLite's INSERT OR REPLACE behavior |
| 141 | if (err.errorType === 'uniqueViolated') { |
| 142 | const items = Array.isArray(toInsert) ? toInsert : [toInsert] |
| 143 | const origItems = Array.isArray(original) ? original : [original] |
| 144 | let pending = items.length |
| 145 | const results = [] |
| 146 | items.forEach((item, i) => { |
| 147 | db[dbName].update({ _id: item._id }, item, {}, (uErr) => { |
| 148 | if (uErr) { |
| 149 | return reject(uErr) |
| 150 | } |
| 151 | results[i] = { ...origItems[i], _id: item._id } |
| 152 | if (--pending === 0) { |
| 153 | resolve(Array.isArray(original) ? results : results[0]) |
| 154 | } |
| 155 | }) |
| 156 | }) |
| 157 | return |
| 158 | } |
| 159 | return reject(err) |
| 160 | } |
| 161 | // Return documents with original (unencrypted) fields + _id |
| 162 | if (Array.isArray(original)) { |
| 163 | const origArr = Array.isArray(inserted) ? inserted : [inserted] |
| 164 | resolve(origArr.map((ins, i) => ({ ...original[i], _id: ins._id }))) |
| 165 | } else { |
| 166 | resolve({ ...original, _id: inserted._id }) |
| 167 | } |
| 168 | }) |
| 169 | } else if (op === 'update') { |
| 170 | const [query, updateObj, options] = args |
| 171 | const qid = query._id || query.id |
| 172 | if (needsEnc(dbName, qid)) { |
| 173 | const newData = updateObj.$set || updateObj |
no test coverage detected