* 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)
| 2366 | * @returns {Promise<Model,boolean>} |
| 2367 | */ |
| 2368 | static async findOrCreate(options) { |
| 2369 | if (!options || !options.where || arguments.length > 1) { |
| 2370 | throw new Error( |
| 2371 | 'Missing where attribute in the options parameter passed to findOrCreate. ' + |
| 2372 | 'Please note that the API has changed, and is now options only (an object with where, defaults keys, transaction etc.)' |
| 2373 | ); |
| 2374 | } |
| 2375 | |
| 2376 | options = { ...options }; |
| 2377 | |
| 2378 | if (options.defaults) { |
| 2379 | const defaults = Object.keys(options.defaults); |
| 2380 | const unknownDefaults = defaults.filter(name => !this.rawAttributes[name]); |
| 2381 | |
| 2382 | if (unknownDefaults.length) { |
| 2383 | logger.warn(`Unknown attributes (${unknownDefaults}) passed to defaults option of findOrCreate`); |
| 2384 | } |
| 2385 | } |
| 2386 | |
| 2387 | if (options.transaction === undefined && this.sequelize.constructor._cls) { |
| 2388 | const t = this.sequelize.constructor._cls.get('transaction'); |
| 2389 | if (t) { |
| 2390 | options.transaction = t; |
| 2391 | } |
| 2392 | } |
| 2393 | |
| 2394 | const internalTransaction = !options.transaction; |
| 2395 | let values; |
| 2396 | let transaction; |
| 2397 | |
| 2398 | try { |
| 2399 | const t = await this.sequelize.transaction(options); |
| 2400 | transaction = t; |
| 2401 | options.transaction = t; |
| 2402 | |
| 2403 | const found = await this.findOne(Utils.defaults({ transaction }, options)); |
| 2404 | if (found !== null) { |
| 2405 | return [found, false]; |
| 2406 | } |
| 2407 | |
| 2408 | values = { ...options.defaults }; |
| 2409 | if (_.isPlainObject(options.where)) { |
| 2410 | values = Utils.defaults(values, options.where); |
| 2411 | } |
| 2412 | |
| 2413 | options.exception = true; |
| 2414 | options.returning = true; |
| 2415 | |
| 2416 | try { |
| 2417 | const created = await this.create(values, options); |
| 2418 | if (created.get(this.primaryKeyAttribute, { raw: true }) === null) { |
| 2419 | // If the query returned an empty result for the primary key, we know that this was actually a unique constraint violation |
| 2420 | throw new sequelizeErrors.UniqueConstraintError(); |
| 2421 | } |
| 2422 | |
| 2423 | return [created, true]; |
| 2424 | } catch (err) { |
| 2425 | if (!(err instanceof sequelizeErrors.UniqueConstraintError)) throw err; |