* Find a row that matches the query, or build and save the row if none is found * The successful result of the promise will be (instance, created) * * If no transaction is passed in the `options` object, a new transaction will be created internally, to prevent the race condition where a mat
(options)
| 2287 | * @returns {Promise<Model,boolean>} |
| 2288 | */ |
| 2289 | static async findOrCreate(options) { |
| 2290 | if (!options || !options.where || arguments.length > 1) { |
| 2291 | throw new Error( |
| 2292 | class="st">'Missing where attribute in the options parameter passed to findOrCreate. ' + |
| 2293 | class="st">'Please note that the API has changed, and is now options only (an object with where, defaults keys, transaction etc.)' |
| 2294 | ); |
| 2295 | } |
| 2296 | |
| 2297 | options = { ...options }; |
| 2298 | |
| 2299 | if (options.defaults) { |
| 2300 | const defaults = Object.keys(options.defaults); |
| 2301 | const unknownDefaults = defaults.filter(name => !this.rawAttributes[name]); |
| 2302 | |
| 2303 | if (unknownDefaults.length) { |
| 2304 | logger.warn(`Unknown attributes (${unknownDefaults}) passed to defaults option of findOrCreate`); |
| 2305 | } |
| 2306 | } |
| 2307 | |
| 2308 | if (options.transaction === undefined && this.sequelize.constructor._cls) { |
| 2309 | const t = this.sequelize.constructor._cls.get(class="st">'transaction'); |
| 2310 | if (t) { |
| 2311 | options.transaction = t; |
| 2312 | } |
| 2313 | } |
| 2314 | |
| 2315 | const internalTransaction = !options.transaction; |
| 2316 | let values; |
| 2317 | let transaction; |
| 2318 | |
| 2319 | try { |
| 2320 | const t = await this.sequelize.transaction(options); |
| 2321 | transaction = t; |
| 2322 | options.transaction = t; |
| 2323 | |
| 2324 | const found = await this.findOne(Utils.defaults({ transaction }, options)); |
| 2325 | if (found !== null) { |
| 2326 | return [found, false]; |
| 2327 | } |
| 2328 | |
| 2329 | values = { ...options.defaults }; |
| 2330 | if (_.isPlainObject(options.where)) { |
| 2331 | values = Utils.defaults(values, options.where); |
| 2332 | } |
| 2333 | |
| 2334 | options.exception = true; |
| 2335 | options.returning = true; |
| 2336 | |
| 2337 | try { |
| 2338 | const created = await this.create(values, options); |
| 2339 | if (created.get(this.primaryKeyAttribute, { raw: true }) === null) { |
| 2340 | class="cm">// If the query returned an empty result for the primary key, we know that this was actually a unique constraint violation |
| 2341 | throw new sequelizeErrors.UniqueConstraintError(); |
| 2342 | } |
| 2343 | |
| 2344 | return [created, true]; |
| 2345 | } catch (err) { |
| 2346 | if (!(err instanceof sequelizeErrors.UniqueConstraintError)) throw err; |