arkormx 2.7.0 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as applyOperationsToPersistedColumnMappingsState, $t as resolvePrismaType, A as getRuntimePrismaClient, An as writeAppliedMigrationsStateToStore, At as buildInverseRelationLine, B as getRegisteredModels, Bt as deriveRelationFieldName, C as getActiveTransactionClient, Cn as markMigrationRun, Ct as applyMigrationRollbackToPrismaSchema, D as getRuntimeDebugHandler, Dn as resolveMigrationStateFilePath, Dt as buildEnumBlock, E as getRuntimeClient, En as removeAppliedMigration, Et as applyOperationsToPrismaSchema, F as loadArkormConfig, Fn as RelationResolutionException, Ft as buildUniqueConstraintLine, G as loadModelsFrom, Gt as formatDefaultValue, H as getRegisteredSeeders, Ht as escapeRegex, I as resetArkormRuntimeForTests, In as ArkormCollection, It as createMigrationTimestamp, J as registerMigrations, Jt as generateMigrationFile, K as loadSeedersFrom, Kt as formatEnumDefaultValue, L as runArkormTransaction, Ln as ArkormException, Lt as deriveCollectionFieldName, M as isDelegateLike, Mn as UnsupportedAdapterFeatureException, Mt as buildModelBlock, N as isQuerySchemaLike, Nn as SetBasedEagerLoader, Nt as buildPrimaryKeyLine, O as getRuntimePaginationCurrentPageResolver, On as supportsDatabaseMigrationState, Ot as buildFieldLine, P as isTransactionCapableClient, Pt as buildRelationLine, Q as resetRuntimeRegistryForTests, Qt as resolveMigrationClassName, R as getRegisteredFactories, Rt as deriveInverseRelationAlias, S as getActiveTransactionAdapter, Sn as markMigrationApplied, St as applyMigrationRollbackToDatabase, T as getRuntimeAdapter, Tn as readAppliedMigrationsStateFromStore, Tt as applyMigrationToPrismaSchema, U as loadFactoriesFrom, Ut as findEnumBlock, V as getRegisteredPaths, Vt as deriveSingularFieldName, W as loadMigrationsFrom, Wt as findModelBlock, X as registerPaths, Xt as pad, Y as registerModels, Yt as getMigrationPlan, Z as registerSeeders, Zt as resolveEnumName, _ as bindAdapterToModels, _n as deleteAppliedMigrationsStateFromStore, _t as PRISMA_ENUM_REGEX, a as HasOneThroughRelation, an as supportsDatabaseReset, at as getPersistedPrimaryKeyGeneration, b as emitRuntimeDebugEvent, bn as getLatestAppliedMigrations, bt as applyCreateTableOperation, c as HasManyRelation, cn as SchemaBuilder, ct as readPersistedColumnMappingsState, d as BelongsToManyRelation, dn as PrimaryKeyGenerationPlanner, dt as resolveColumnMappingsFilePath, en as runMigrationWithPrisma, et as createEmptyPersistedColumnMappingsState, f as Relation, fn as ForeignKeyBuilder, ft as resolvePersistedMetadataFeatures, g as awaitConfiguredModelsRegistration, gn as createEmptyAppliedMigrationsState, gt as PRISMA_ENUM_MEMBER_REGEX, h as URLDriver, hn as computeMigrationChecksum, ht as writePersistedColumnMappingsState, i as MorphManyRelation, in as supportsDatabaseMigrationExecution, it as getPersistedEnumTsType, j as getUserConfig, jn as RuntimeModuleLoader, jt as buildMigrationSource, k as getRuntimePaginationURLDriverFactory, kn as writeAppliedMigrationsState, kt as buildIndexLine, l as BelongsToRelation, ln as EnumBuilder, lt as rebuildPersistedColumnMappingsState, m as Paginator, mn as buildMigrationRunId, mt as validatePersistedMetadataFeaturesForMigrations, n as MorphToManyRelation, nn as stripPrismaSchemaModelsAndEnums, nt as getPersistedColumnMap, o as HasOneRelation, on as toMigrationFileSlug, ot as getPersistedTableMetadata, p as LengthAwarePaginator, pn as buildMigrationIdentity, pt as syncPersistedColumnMappingsFromState, q as registerFactories, qt as formatRelationAction, r as MorphOneRelation, rn as supportsDatabaseCreation, rt as getPersistedEnumMap, s as HasManyThroughRelation, sn as toModelName, st as getPersistedTimestampColumns, t as MorphToRelation, tn as runPrismaCommand, tt as deletePersistedColumnMappingsState, un as TableBuilder, ut as resetPersistedColumnMappingsCache, v as configureArkormRuntime, vn as findAppliedMigration, vt as PRISMA_MODEL_REGEX, w as getDefaultStubsPath, wn as readAppliedMigrationsState, wt as applyMigrationToDatabase, x as ensureArkormConfigLoading, xn as isMigrationApplied, xt as applyDropTableOperation, y as defineConfig, yn as getLastMigrationRun, yt as applyAlterTableOperation, z as getRegisteredMigrations, zt as deriveRelationAlias } from "./relationship-BuwKUTOb.mjs";
1
+ import { $ as applyOperationsToPersistedColumnMappingsState, $t as resolvePrismaType, A as getRuntimePrismaClient, An as writeAppliedMigrationsStateToStore, At as buildInverseRelationLine, B as getRegisteredModels, Bt as deriveRelationFieldName, C as getActiveTransactionClient, Cn as markMigrationRun, Ct as applyMigrationRollbackToPrismaSchema, D as getRuntimeDebugHandler, Dn as resolveMigrationStateFilePath, Dt as buildEnumBlock, E as getRuntimeClient, En as removeAppliedMigration, Et as applyOperationsToPrismaSchema, F as loadArkormConfig, Fn as RelationResolutionException, Ft as buildUniqueConstraintLine, G as loadModelsFrom, Gt as formatDefaultValue, H as getRegisteredSeeders, Ht as escapeRegex, I as resetArkormRuntimeForTests, In as ArkormCollection, It as createMigrationTimestamp, J as registerMigrations, Jt as generateMigrationFile, K as loadSeedersFrom, Kt as formatEnumDefaultValue, L as runArkormTransaction, Ln as ArkormException, Lt as deriveCollectionFieldName, M as isDelegateLike, Mn as UnsupportedAdapterFeatureException, Mt as buildModelBlock, N as isQuerySchemaLike, Nn as SetBasedEagerLoader, Nt as buildPrimaryKeyLine, O as getRuntimePaginationCurrentPageResolver, On as supportsDatabaseMigrationState, Ot as buildFieldLine, P as isTransactionCapableClient, Pt as buildRelationLine, Q as resetRuntimeRegistryForTests, Qt as resolveMigrationClassName, R as getRegisteredFactories, Rt as deriveInverseRelationAlias, S as getActiveTransactionAdapter, Sn as markMigrationApplied, St as applyMigrationRollbackToDatabase, T as getRuntimeAdapter, Tn as readAppliedMigrationsStateFromStore, Tt as applyMigrationToPrismaSchema, U as loadFactoriesFrom, Ut as findEnumBlock, V as getRegisteredPaths, Vt as deriveSingularFieldName, W as loadMigrationsFrom, Wt as findModelBlock, X as registerPaths, Xt as pad, Y as registerModels, Yt as getMigrationPlan, Z as registerSeeders, Zt as resolveEnumName, _ as bindAdapterToModels, _n as deleteAppliedMigrationsStateFromStore, _t as PRISMA_ENUM_REGEX, a as HasOneThroughRelation, an as supportsDatabaseReset, at as getPersistedPrimaryKeyGeneration, b as emitRuntimeDebugEvent, bn as getLatestAppliedMigrations, bt as applyCreateTableOperation, c as HasManyRelation, cn as SchemaBuilder, ct as readPersistedColumnMappingsState, d as BelongsToManyRelation, dn as PrimaryKeyGenerationPlanner, dt as resolveColumnMappingsFilePath, en as runMigrationWithPrisma, et as createEmptyPersistedColumnMappingsState, f as Relation, fn as ForeignKeyBuilder, ft as resolvePersistedMetadataFeatures, g as awaitConfiguredModelsRegistration, gn as createEmptyAppliedMigrationsState, gt as PRISMA_ENUM_MEMBER_REGEX, h as URLDriver, hn as computeMigrationChecksum, ht as writePersistedColumnMappingsState, i as MorphManyRelation, in as supportsDatabaseMigrationExecution, it as getPersistedEnumTsType, j as getUserConfig, jn as RuntimeModuleLoader, jt as buildMigrationSource, k as getRuntimePaginationURLDriverFactory, kn as writeAppliedMigrationsState, kt as buildIndexLine, l as BelongsToRelation, ln as EnumBuilder, lt as rebuildPersistedColumnMappingsState, m as Paginator, mn as buildMigrationRunId, mt as validatePersistedMetadataFeaturesForMigrations, n as MorphToManyRelation, nn as stripPrismaSchemaModelsAndEnums, nt as getPersistedColumnMap, o as HasOneRelation, on as toMigrationFileSlug, ot as getPersistedTableMetadata, p as LengthAwarePaginator, pn as buildMigrationIdentity, pt as syncPersistedColumnMappingsFromState, q as registerFactories, qt as formatRelationAction, r as MorphOneRelation, rn as supportsDatabaseCreation, rt as getPersistedEnumMap, s as HasManyThroughRelation, sn as toModelName, st as getPersistedTimestampColumns, t as MorphToRelation, tn as runPrismaCommand, tt as deletePersistedColumnMappingsState, un as TableBuilder, ut as resetPersistedColumnMappingsCache, v as configureArkormRuntime, vn as findAppliedMigration, vt as PRISMA_MODEL_REGEX, w as getDefaultStubsPath, wn as readAppliedMigrationsState, wt as applyMigrationToDatabase, x as ensureArkormConfigLoading, xn as isMigrationApplied, xt as applyDropTableOperation, y as defineConfig, yn as getLastMigrationRun, yt as applyAlterTableOperation, z as getRegisteredMigrations, zt as deriveRelationAlias } from "./relationship--l8RA_yy.mjs";
2
2
  import { Pool } from "pg";
3
3
  import { join, resolve } from "node:path";
4
4
  import { createRequire } from "module";
@@ -3322,6 +3322,7 @@ var MigrateCommand = class extends Command {
3322
3322
  */
3323
3323
  async handle() {
3324
3324
  this.app.command = this;
3325
+ await loadArkormConfig();
3325
3326
  const configuredMigrationsDir = this.app.getConfig("paths")?.migrations ?? join(process.cwd(), "database", "migrations");
3326
3327
  const migrationDirs = this.resolveMigrationDirectories(configuredMigrationsDir);
3327
3328
  if (migrationDirs.length === 0 && getRegisteredMigrations().length === 0) return void this.error(`Error: Migrations directory not found: ${this.app.formatPathForLog(configuredMigrationsDir)}`);
@@ -3362,14 +3363,17 @@ var MigrateCommand = class extends Command {
3362
3363
  this.success("No pending migration classes to apply.");
3363
3364
  return;
3364
3365
  }
3365
- if (useDatabaseMigrations) try {
3366
- await validatePersistedMetadataFeaturesForMigrations(pending, persistedFeatures);
3367
- } catch (error) {
3368
- this.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
3369
- return;
3370
- }
3366
+ let columnMappingsState = createEmptyPersistedColumnMappingsState();
3371
3367
  for (const [MigrationClassItem] of pending) {
3372
3368
  if (useDatabaseMigrations) {
3369
+ const planned = await this.runWithDatabaseCreationRetry(adapter, () => getMigrationPlan(MigrationClassItem, "up"));
3370
+ if (!planned.ok) return;
3371
+ try {
3372
+ columnMappingsState = applyOperationsToPersistedColumnMappingsState(columnMappingsState, planned.value, persistedFeatures);
3373
+ } catch (error) {
3374
+ this.error(`Error: ${error instanceof Error ? error.message : String(error)}`);
3375
+ return;
3376
+ }
3373
3377
  if (!(await this.runWithDatabaseCreationRetry(adapter, () => applyMigrationToDatabase(adapter, MigrationClassItem))).ok) return;
3374
3378
  continue;
3375
3379
  }
@@ -5634,6 +5638,56 @@ var QueryBuilder = class QueryBuilder {
5634
5638
  if (!model) throw new ModelNotFoundException(this.model.name, "Record not found.");
5635
5639
  return model;
5636
5640
  }
5641
+ /**
5642
+ * Returns the first record matching the given attributes or instantiates a
5643
+ * new, unpersisted model populated with the merged attributes and values.
5644
+ *
5645
+ * @param attributes
5646
+ * @param values
5647
+ * @returns
5648
+ */
5649
+ async firstOrNew(attributes, values = {}) {
5650
+ const existing = await this.clone().where(attributes).first();
5651
+ if (existing) return existing;
5652
+ const ModelConstructor = this.model;
5653
+ return new ModelConstructor({
5654
+ ...attributes,
5655
+ ...values
5656
+ });
5657
+ }
5658
+ /**
5659
+ * Returns the first record matching the given attributes or creates and
5660
+ * persists a new record populated with the merged attributes and values.
5661
+ *
5662
+ * @param attributes
5663
+ * @param values
5664
+ * @returns
5665
+ */
5666
+ async firstOrCreate(attributes, values = {}) {
5667
+ const existing = await this.clone().where(attributes).first();
5668
+ if (existing) return existing;
5669
+ return await this.create({
5670
+ ...attributes,
5671
+ ...values
5672
+ });
5673
+ }
5674
+ async firstOr(columnsOrCallback, maybeCallback) {
5675
+ const callback = typeof columnsOrCallback === "function" ? columnsOrCallback : maybeCallback;
5676
+ if (!callback) throw new QueryConstraintException("firstOr requires a fallback callback.", {
5677
+ operation: "firstOr",
5678
+ model: this.model.name
5679
+ });
5680
+ if (Array.isArray(columnsOrCallback) && columnsOrCallback.length > 0) {
5681
+ const select = columnsOrCallback.reduce((all, column) => {
5682
+ all[column] = true;
5683
+ return all;
5684
+ }, {});
5685
+ this.select(select);
5686
+ }
5687
+ const found = await this.first();
5688
+ if (found) return found;
5689
+ return callback();
5690
+ }
5637
5691
  async find(value, key) {
5638
5692
  const resolvedKey = key ?? this.model.getPrimaryKey();
5639
5693
  return this.where({ [resolvedKey]: value }).first();
@@ -5843,6 +5897,23 @@ var QueryBuilder = class QueryBuilder {
5843
5897
  }
5844
5898
  return await this.clone().where(attributes).update(resolvedValues) != null;
5845
5899
  }
5900
+ /**
5901
+ * Update the first record matching the given attributes, or create a new
5902
+ * record populated with the merged attributes and values when none exists.
5903
+ *
5904
+ * @param attributes
5905
+ * @param values
5906
+ * @returns
5907
+ */
5908
+ async updateOrCreate(attributes, values = {}) {
5909
+ const existing = await this.clone().where(attributes).first();
5910
+ if (!existing) return await this.create({
5911
+ ...attributes,
5912
+ ...values
5913
+ });
5914
+ if (Object.keys(values).length === 0) return existing;
5915
+ return await this.clone().where(attributes).update(values);
5916
+ }
5846
5917
  shouldFallbackUpdateOrInsertUpsert(error) {
5847
5918
  if (!(error instanceof QueryExecutionException)) return false;
5848
5919
  const cause = error.cause;
@@ -5894,13 +5965,25 @@ var QueryBuilder = class QueryBuilder {
5894
5965
  if (!this.isUniqueWhere(where) && directSpec && typeof adapter.deleteFirst === "function") {
5895
5966
  const deleted = await adapter.deleteFirst(directSpec);
5896
5967
  if (!deleted) return null;
5897
- return this.model.hydrate(deleted);
5968
+ return this.hydrateDeleted(deleted);
5898
5969
  }
5899
5970
  const uniqueWhere = await this.resolveUniqueWhere(where, false);
5900
5971
  if (!uniqueWhere) return null;
5901
5972
  const deleted = await this.executeDeleteRow(uniqueWhere, false);
5902
5973
  if (!deleted) return null;
5903
- return this.model.hydrate(deleted);
5974
+ return this.hydrateDeleted(deleted);
5975
+ }
5976
+ /**
5977
+ * Hydrate a row that was just deleted, marking the resulting model as no
5978
+ * longer existing in the database.
5979
+ *
5980
+ * @param attributes
5981
+ * @returns
5982
+ */
5983
+ hydrateDeleted(attributes) {
5984
+ const model = this.model.hydrate(attributes);
5985
+ model.exists = false;
5986
+ return model;
5904
5987
  }
5905
5988
  /**
5906
5989
  * Deletes the first record matching the current query constraints and throws
@@ -7269,9 +7352,12 @@ var Model = class Model {
7269
7352
  this.hidden = [];
7270
7353
  this.visible = [];
7271
7354
  this.appends = [];
7355
+ this.exists = false;
7356
+ this.wasRecentlyCreated = false;
7272
7357
  this.attributes = {};
7273
7358
  this.original = {};
7274
7359
  this.changes = {};
7360
+ this.previous = {};
7275
7361
  this.touchedAttributes = /* @__PURE__ */ new Set();
7276
7362
  this.fill(attributes);
7277
7363
  return new Proxy(this, {
@@ -7631,6 +7717,68 @@ var Model = class Model {
7631
7717
  return this.query().scope(name, ...args);
7632
7718
  }
7633
7719
  /**
7720
+ * Start a query constrained by the given where clause.
7721
+ *
7722
+ * @param this
7723
+ * @param where
7724
+ * @returns
7725
+ */
7726
+ static where(where) {
7727
+ return this.query().where(where);
7728
+ }
7729
+ /**
7730
+ * Retrieve all records for the model.
7731
+ *
7732
+ * @param this
7733
+ * @returns
7734
+ */
7735
+ static async all() {
7736
+ return await this.query().get();
7737
+ }
7738
+ /**
7739
+ * Create and persist a new record, returning the hydrated model instance.
7740
+ *
7741
+ * @param this
7742
+ * @param data
7743
+ * @returns
7744
+ */
7745
+ static async create(data) {
7746
+ return await this.query().create(data);
7747
+ }
7748
+ /**
7749
+ * Insert new records or update existing records by one or more unique keys.
7750
+ *
7751
+ * @param this
7752
+ * @param values
7753
+ * @param uniqueBy
7754
+ * @param update
7755
+ * @returns
7756
+ */
7757
+ static async upsert(values, uniqueBy, update = null) {
7758
+ return await this.query().upsert(values, uniqueBy, update);
7759
+ }
7760
+ /**
7761
+ * Delete records by their primary key(s), dispatching model events for each
7762
+ * matched record. Returns the number of records deleted.
7763
+ *
7764
+ * @param this
7765
+ * @param ids
7766
+ * @returns
7767
+ */
7768
+ static async destroy(ids) {
7769
+ const constructor = this;
7770
+ const identifiers = (Array.isArray(ids) ? ids : [ids]).filter((identifier, index, all) => all.indexOf(identifier) === index);
7771
+ const primaryKey = constructor.getPrimaryKey();
7772
+ let deleted = 0;
7773
+ for (const identifier of identifiers) {
7774
+ const model = await constructor.query().where({ [primaryKey]: identifier }).first();
7775
+ if (!model) continue;
7776
+ await model.delete();
7777
+ deleted += 1;
7778
+ }
7779
+ return deleted;
7780
+ }
7781
+ /**
7634
7782
  * Get the soft delete configuration for the model, including whether
7635
7783
  * soft deletes are enabled and the name of the deleted at column.
7636
7784
  *
@@ -7653,6 +7801,7 @@ var Model = class Model {
7653
7801
  const model = new this(attributes);
7654
7802
  model.syncOriginal();
7655
7803
  model.syncChanges({});
7804
+ model.exists = true;
7656
7805
  return model;
7657
7806
  }
7658
7807
  /**
@@ -7663,7 +7812,8 @@ var Model = class Model {
7663
7812
  * @returns
7664
7813
  */
7665
7814
  static hydrateMany(attributes) {
7666
- return attributes.map((attribute) => new this(attribute));
7815
+ const constructor = this;
7816
+ return attributes.map((attribute) => constructor.hydrate(attribute));
7667
7817
  }
7668
7818
  /**
7669
7819
  * Hydrate a model instance and dispatch the retrieved lifecycle event.
@@ -7711,6 +7861,11 @@ var Model = class Model {
7711
7861
  return false;
7712
7862
  }
7713
7863
  }
7864
+ async updateOrFail(attributes) {
7865
+ const primaryKey = this.constructor.getPrimaryKey();
7866
+ if (this.getAttribute(primaryKey) == null) throw new ArkormException(primaryKey === "id" ? "Cannot update a model without an id." : `Cannot update a model without a [${primaryKey}] value.`);
7867
+ return await this.fill(attributes).saveOrFail();
7868
+ }
7714
7869
  getAttribute(key) {
7715
7870
  const attributeMutator = this.resolveAttributeMutator(key);
7716
7871
  const mutator = this.resolveGetMutator(key);
@@ -7734,29 +7889,35 @@ var Model = class Model {
7734
7889
  return this;
7735
7890
  }
7736
7891
  /**
7737
- * Save the model to the database.
7738
- * If the model has an identifier (id), it will perform an update.
7739
- * Otherwise, it will perform a create.
7740
- *
7741
- * @returns
7892
+ * Save the model to the database.
7893
+ * If the model already exists in the database it performs an update;
7894
+ * otherwise it performs an insert. Existence is tracked through the
7895
+ * `exists` flag rather than the presence of a primary-key value, so a model
7896
+ * built with an explicit primary key still inserts on its first save.
7897
+ *
7898
+ * @returns
7742
7899
  */
7743
7900
  async save() {
7744
7901
  const constructor = this.constructor;
7745
7902
  const primaryKey = constructor.getPrimaryKey();
7746
- const identifier = this.getAttribute(primaryKey);
7747
7903
  const previousOriginal = this.getOriginal();
7748
- if (identifier == null) {
7904
+ if (!this.exists) {
7749
7905
  await Model.dispatchEvent(constructor, "saving", this);
7750
7906
  await Model.dispatchEvent(constructor, "creating", this);
7751
7907
  const payload = this.normalizePersistenceAttributes(this.getRawAttributes());
7752
7908
  const model = await constructor.query().create(payload);
7753
7909
  this.fill(model.getRawAttributes());
7754
7910
  this.syncChanges(previousOriginal);
7911
+ this.syncPrevious(previousOriginal);
7755
7912
  this.syncOriginal();
7913
+ this.exists = true;
7914
+ this.wasRecentlyCreated = true;
7756
7915
  await Model.dispatchEvent(constructor, "created", this);
7757
7916
  await Model.dispatchEvent(constructor, "saved", this);
7758
7917
  return this;
7759
7918
  }
7919
+ const identifier = this.getAttribute(primaryKey);
7920
+ if (identifier == null) throw new ArkormException(primaryKey === "id" ? "Cannot update an existing model without an id." : `Cannot update an existing model without a [${primaryKey}] value.`);
7760
7921
  await Model.dispatchEvent(constructor, "saving", this);
7761
7922
  await Model.dispatchEvent(constructor, "updating", this);
7762
7923
  const payload = this.normalizePersistenceAttributes(this.getDirtyAttributes());
@@ -7764,6 +7925,7 @@ var Model = class Model {
7764
7925
  const model = await constructor.query().where({ [primaryKey]: identifier }).update(payload);
7765
7926
  this.fill(model.getRawAttributes());
7766
7927
  this.syncChanges(previousOriginal);
7928
+ this.syncPrevious(previousOriginal);
7767
7929
  this.syncOriginal();
7768
7930
  await Model.dispatchEvent(constructor, "updated", this);
7769
7931
  await Model.dispatchEvent(constructor, "saved", this);
@@ -7778,6 +7940,15 @@ var Model = class Model {
7778
7940
  return await Model.withoutEvents(() => this.save());
7779
7941
  }
7780
7942
  /**
7943
+ * Save the model within a transaction, rolling back and rethrowing if the
7944
+ * operation fails. Unlike update(), this never swallows errors.
7945
+ *
7946
+ * @returns
7947
+ */
7948
+ async saveOrFail() {
7949
+ return await this.constructor.transaction(async () => await this.save());
7950
+ }
7951
+ /**
7781
7952
  * Delete the model from the database.
7782
7953
  * If soft deletes are enabled, it will perform a soft delete by
7783
7954
  * setting the deleted at column to the current date.
@@ -7805,6 +7976,7 @@ var Model = class Model {
7805
7976
  this.fill(deleted.getRawAttributes());
7806
7977
  this.syncChanges(previousOriginal);
7807
7978
  this.syncOriginal();
7979
+ this.exists = false;
7808
7980
  await Model.dispatchEvent(constructor, "deleted", this);
7809
7981
  return this;
7810
7982
  }
@@ -7817,6 +7989,15 @@ var Model = class Model {
7817
7989
  return await Model.withoutEvents(() => this.delete());
7818
7990
  }
7819
7991
  /**
7992
+ * Delete the model within a transaction, rolling back and rethrowing if the
7993
+ * operation fails.
7994
+ *
7995
+ * @returns
7996
+ */
7997
+ async deleteOrFail() {
7998
+ return await this.constructor.transaction(async () => await this.delete());
7999
+ }
8000
+ /**
7820
8001
  * Permanently delete the model from the database, regardless of whether soft
7821
8002
  * deletes are enabled.
7822
8003
  *
@@ -7834,6 +8015,7 @@ var Model = class Model {
7834
8015
  this.fill(deleted.getRawAttributes());
7835
8016
  this.syncChanges(previousOriginal);
7836
8017
  this.syncOriginal();
8018
+ this.exists = false;
7837
8019
  await Model.dispatchEvent(constructor, "deleted", this);
7838
8020
  await Model.dispatchEvent(constructor, "forceDeleted", this);
7839
8021
  return this;
@@ -7988,6 +8170,25 @@ var Model = class Model {
7988
8170
  return keyList.some((key) => Object.prototype.hasOwnProperty.call(this.changes, key));
7989
8171
  }
7990
8172
  /**
8173
+ * Get the attributes that were changed during the last successful
8174
+ * persistence operation.
8175
+ *
8176
+ * @returns
8177
+ */
8178
+ getChanges() {
8179
+ return Object.entries(this.changes).reduce((all, [key, value]) => {
8180
+ all[key] = Model.cloneAttributeValue(value);
8181
+ return all;
8182
+ }, {});
8183
+ }
8184
+ getPrevious(key) {
8185
+ if (typeof key === "string") return Model.cloneAttributeValue(this.previous[key]);
8186
+ return Object.entries(this.previous).reduce((all, [previousKey, value]) => {
8187
+ all[previousKey] = Model.cloneAttributeValue(value);
8188
+ return all;
8189
+ }, {});
8190
+ }
8191
+ /**
7991
8192
  * Convert the model instance to a plain object, applying visibility
7992
8193
  * rules, appends, and mutators.
7993
8194
  *
@@ -8404,6 +8605,18 @@ var Model = class Model {
8404
8605
  }, {});
8405
8606
  }
8406
8607
  /**
8608
+ * Capture the attribute snapshot that was persisted before the most recent
8609
+ * save so it can be read back via getPrevious().
8610
+ *
8611
+ * @param previousOriginal
8612
+ */
8613
+ syncPrevious(previousOriginal) {
8614
+ this.previous = Object.entries(previousOriginal).reduce((all, [key, value]) => {
8615
+ all[key] = Model.cloneAttributeValue(value);
8616
+ return all;
8617
+ }, {});
8618
+ }
8619
+ /**
8407
8620
  * Resolve lifecycle state for the provided model class.
8408
8621
  *
8409
8622
  * @param modelClass
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_relationship = require('../relationship-B8FaJYIx.cjs');
2
+ const require_relationship = require('../relationship-WiXlopzY.cjs');
3
3
 
4
4
  exports.BelongsToManyRelation = require_relationship.BelongsToManyRelation;
5
5
  exports.BelongsToRelation = require_relationship.BelongsToRelation;
@@ -1,2 +1,2 @@
1
- import { Ao as MorphManyRelation, Do as MorphToRelation, Eo as SetBasedEagerLoader, Fo as BelongsToRelation, Io as SingleResultRelation, Lo as BelongsToManyRelation, Mo as HasOneRelation, No as HasManyThroughRelation, Oo as MorphToManyRelation, Po as HasManyRelation, Ro as Relation, jo as HasOneThroughRelation, ko as MorphOneRelation, zo as RelationTableLoader } from "../index-Dnn0lsDy.cjs";
1
+ import { Ao as MorphManyRelation, Do as MorphToRelation, Eo as SetBasedEagerLoader, Fo as BelongsToRelation, Io as SingleResultRelation, Lo as BelongsToManyRelation, Mo as HasOneRelation, No as HasManyThroughRelation, Oo as MorphToManyRelation, Po as HasManyRelation, Ro as Relation, jo as HasOneThroughRelation, ko as MorphOneRelation, zo as RelationTableLoader } from "../index-4mi5sLRA.cjs";
2
2
  export { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasManyThroughRelation, HasOneRelation, HasOneThroughRelation, MorphManyRelation, MorphOneRelation, MorphToManyRelation, MorphToRelation, Relation, RelationTableLoader, SetBasedEagerLoader, SingleResultRelation };
@@ -1,2 +1,2 @@
1
- import { Ao as MorphManyRelation, Do as MorphToRelation, Eo as SetBasedEagerLoader, Fo as BelongsToRelation, Io as SingleResultRelation, Lo as BelongsToManyRelation, Mo as HasOneRelation, No as HasManyThroughRelation, Oo as MorphToManyRelation, Po as HasManyRelation, Ro as Relation, jo as HasOneThroughRelation, ko as MorphOneRelation, zo as RelationTableLoader } from "../index-C77nMASp.mjs";
1
+ import { Ao as MorphManyRelation, Do as MorphToRelation, Eo as SetBasedEagerLoader, Fo as BelongsToRelation, Io as SingleResultRelation, Lo as BelongsToManyRelation, Mo as HasOneRelation, No as HasManyThroughRelation, Oo as MorphToManyRelation, Po as HasManyRelation, Ro as Relation, jo as HasOneThroughRelation, ko as MorphOneRelation, zo as RelationTableLoader } from "../index-De8zXqTD.mjs";
2
2
  export { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasManyThroughRelation, HasOneRelation, HasOneThroughRelation, MorphManyRelation, MorphOneRelation, MorphToManyRelation, MorphToRelation, Relation, RelationTableLoader, SetBasedEagerLoader, SingleResultRelation };
@@ -1,3 +1,3 @@
1
- import { Nn as SetBasedEagerLoader, Pn as RelationTableLoader, a as HasOneThroughRelation, c as HasManyRelation, d as BelongsToManyRelation, f as Relation, i as MorphManyRelation, l as BelongsToRelation, n as MorphToManyRelation, o as HasOneRelation, r as MorphOneRelation, s as HasManyThroughRelation, t as MorphToRelation, u as SingleResultRelation } from "../relationship-BuwKUTOb.mjs";
1
+ import { Nn as SetBasedEagerLoader, Pn as RelationTableLoader, a as HasOneThroughRelation, c as HasManyRelation, d as BelongsToManyRelation, f as Relation, i as MorphManyRelation, l as BelongsToRelation, n as MorphToManyRelation, o as HasOneRelation, r as MorphOneRelation, s as HasManyThroughRelation, t as MorphToRelation, u as SingleResultRelation } from "../relationship--l8RA_yy.mjs";
2
2
 
3
3
  export { BelongsToManyRelation, BelongsToRelation, HasManyRelation, HasManyThroughRelation, HasOneRelation, HasOneThroughRelation, MorphManyRelation, MorphOneRelation, MorphToManyRelation, MorphToRelation, Relation, RelationTableLoader, SetBasedEagerLoader, SingleResultRelation };
@@ -4343,7 +4343,9 @@ var Relation = class {
4343
4343
  * @returns
4344
4344
  */
4345
4345
  make(attributes = {}) {
4346
- return this.getRelatedModelConstructor().hydrate(this.mergeCreationAttributes(attributes));
4346
+ const model = this.getRelatedModelConstructor().hydrate(this.mergeCreationAttributes(attributes));
4347
+ model.exists = false;
4348
+ return model;
4347
4349
  }
4348
4350
  /**
4349
4351
  * Create new instances of the related model with the given attributes and relationship
@@ -4371,7 +4371,9 @@ var Relation = class {
4371
4371
  * @returns
4372
4372
  */
4373
4373
  make(attributes = {}) {
4374
- return this.getRelatedModelConstructor().hydrate(this.mergeCreationAttributes(attributes));
4374
+ const model = this.getRelatedModelConstructor().hydrate(this.mergeCreationAttributes(attributes));
4375
+ model.exists = false;
4376
+ return model;
4375
4377
  }
4376
4378
  /**
4377
4379
  * Create new instances of the related model with the given attributes and relationship
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkormx",
3
- "version": "2.7.0",
3
+ "version": "2.8.1",
4
4
  "description": "Modern TypeScript-first ORM for Node.js.",
5
5
  "keywords": [
6
6
  "orm",