arkormx 2.5.2 → 2.5.4

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.
@@ -2933,6 +2933,8 @@ const userConfig = {
2933
2933
  };
2934
2934
  let runtimeConfigLoaded = false;
2935
2935
  let runtimeConfigLoadingPromise;
2936
+ let runtimeModelRegistrationPromise;
2937
+ let runtimeModelRegistrationGeneration = 0;
2936
2938
  let runtimeClientResolver;
2937
2939
  let runtimeAdapter;
2938
2940
  let runtimePaginationURLDriverFactory;
@@ -2998,6 +3000,51 @@ const mergeFeatureConfig = (features) => {
2998
3000
  ...features ?? {}
2999
3001
  };
3000
3002
  };
3003
+ const resolveRuntimeModelsDirectory = (directory) => {
3004
+ if ((0, fs.existsSync)(directory)) return directory;
3005
+ const buildOutput = userConfig.paths?.buildOutput;
3006
+ if (typeof buildOutput !== "string" || buildOutput.trim().length === 0) return directory;
3007
+ const relativeSource = path.default.relative(process.cwd(), directory);
3008
+ if (!relativeSource || relativeSource.startsWith("..")) return directory;
3009
+ const mappedDirectory = path.default.join(buildOutput, relativeSource);
3010
+ return (0, fs.existsSync)(mappedDirectory) ? mappedDirectory : directory;
3011
+ };
3012
+ const collectRuntimeModelFiles = (directory) => {
3013
+ if (!(0, fs.existsSync)(directory)) return [];
3014
+ return (0, fs.readdirSync)(directory, { withFileTypes: true }).flatMap((entry) => {
3015
+ const entryPath = path.default.join(directory, entry.name);
3016
+ if (entry.isDirectory()) return collectRuntimeModelFiles(entryPath);
3017
+ if (!entry.isFile() || !/\.(ts|tsx|mts|cts|js|mjs|cjs)$/i.test(entry.name)) return [];
3018
+ if (/\.d\.(ts|mts|cts)$/i.test(entry.name)) return [];
3019
+ return [entryPath];
3020
+ });
3021
+ };
3022
+ const isModelConstructor = (value) => {
3023
+ if (typeof value !== "function") return false;
3024
+ const candidate = value;
3025
+ return typeof candidate.query === "function" && typeof candidate.hydrate === "function" && typeof candidate.getTable === "function" && typeof candidate.getPrimaryKey === "function";
3026
+ };
3027
+ const registerConfiguredModels = async (generation) => {
3028
+ const configured = userConfig.paths?.models;
3029
+ const additional = getRegisteredPaths("models");
3030
+ const files = [...typeof configured === "string" ? [configured] : [], ...additional].map((directory) => resolveRuntimeModelsDirectory(path.default.isAbsolute(directory) ? directory : path.default.resolve(process.cwd(), directory))).filter((directory, index, all) => all.indexOf(directory) === index).flatMap(collectRuntimeModelFiles);
3031
+ const models = (await Promise.all(files.map(async (file) => {
3032
+ try {
3033
+ return await RuntimeModuleLoader.load(file);
3034
+ } catch {
3035
+ return null;
3036
+ }
3037
+ }))).flatMap((module) => module ? Object.values(module).filter(isModelConstructor) : []);
3038
+ if (generation === runtimeModelRegistrationGeneration) registerModels(models);
3039
+ };
3040
+ const scheduleConfiguredModelRegistration = () => {
3041
+ const generation = runtimeModelRegistrationGeneration;
3042
+ runtimeModelRegistrationPromise = (runtimeModelRegistrationPromise ?? Promise.resolve()).then(async () => await registerConfiguredModels(generation));
3043
+ return runtimeModelRegistrationPromise;
3044
+ };
3045
+ const awaitConfiguredModelsRegistration = async () => {
3046
+ if (runtimeModelRegistrationPromise) await runtimeModelRegistrationPromise;
3047
+ };
3001
3048
  /**
3002
3049
  * Define the ArkORM runtime configuration. This function can be used to provide.
3003
3050
  *
@@ -3058,6 +3105,7 @@ const configureArkormRuntime = (client, options = {}) => {
3058
3105
  runtimePaginationURLDriverFactory = nextConfig.pagination?.urlDriver;
3059
3106
  runtimePaginationCurrentPageResolver = nextConfig.pagination?.resolveCurrentPage;
3060
3107
  runtimeDebugHandler = resolveDebugHandler(nextConfig.debug);
3108
+ scheduleConfiguredModelRegistration();
3061
3109
  const bootClient = resolveClient(resolvedClient);
3062
3110
  options.boot?.({
3063
3111
  client: bootClient,
@@ -3078,6 +3126,8 @@ const resetArkormRuntimeForTests = () => {
3078
3126
  });
3079
3127
  runtimeConfigLoaded = false;
3080
3128
  runtimeConfigLoadingPromise = void 0;
3129
+ runtimeModelRegistrationPromise = void 0;
3130
+ runtimeModelRegistrationGeneration++;
3081
3131
  runtimeClientResolver = void 0;
3082
3132
  runtimeAdapter = void 0;
3083
3133
  runtimePaginationURLDriverFactory = void 0;
@@ -3154,21 +3204,30 @@ const loadRuntimeConfigSync = () => {
3154
3204
  * @returns
3155
3205
  */
3156
3206
  const loadArkormConfig = async () => {
3157
- if (runtimeConfigLoaded) return;
3207
+ if (runtimeConfigLoaded) {
3208
+ await awaitConfiguredModelsRegistration();
3209
+ return;
3210
+ }
3158
3211
  if (runtimeConfigLoadingPromise) return await runtimeConfigLoadingPromise;
3159
- if (loadRuntimeConfigSync()) return;
3212
+ if (loadRuntimeConfigSync()) {
3213
+ await awaitConfiguredModelsRegistration();
3214
+ return;
3215
+ }
3160
3216
  runtimeConfigLoadingPromise = (async () => {
3161
3217
  const configPaths = [path.default.join(process.cwd(), "arkormx.config.js"), path.default.join(process.cwd(), "arkormx.config.ts")];
3162
3218
  for (const configPath of configPaths) {
3163
3219
  if (!(0, fs.existsSync)(configPath)) continue;
3164
3220
  try {
3165
3221
  resolveAndApplyConfig(await importConfigFile(configPath));
3222
+ await awaitConfiguredModelsRegistration();
3166
3223
  return;
3167
3224
  } catch {
3168
3225
  continue;
3169
3226
  }
3170
3227
  }
3171
3228
  runtimeConfigLoaded = true;
3229
+ await scheduleConfiguredModelRegistration();
3230
+ await awaitConfiguredModelsRegistration();
3172
3231
  })();
3173
3232
  await runtimeConfigLoadingPromise;
3174
3233
  };
@@ -3553,6 +3612,77 @@ var Relation = class {
3553
3612
  return this.constrain((query) => query.where(where));
3554
3613
  }
3555
3614
  /**
3615
+ * Adds an OR where clause to the query.
3616
+ *
3617
+ * @param where
3618
+ * @returns
3619
+ */
3620
+ orWhere(where) {
3621
+ return this.constrain((query) => query.orWhere(where));
3622
+ }
3623
+ /**
3624
+ * Adds a NOT where clause to the query.
3625
+ *
3626
+ * @param where
3627
+ * @returns
3628
+ */
3629
+ whereNot(where) {
3630
+ return this.constrain((query) => query.whereNot(where));
3631
+ }
3632
+ /**
3633
+ * Adds an OR NOT where clause to the query.
3634
+ *
3635
+ * @param where
3636
+ * @returns
3637
+ */
3638
+ orWhereNot(where) {
3639
+ return this.constrain((query) => query.orWhereNot(where));
3640
+ }
3641
+ /**
3642
+ * Adds a null check for a key.
3643
+ *
3644
+ * @param key
3645
+ * @returns
3646
+ */
3647
+ whereNull(key) {
3648
+ return this.constrain((query) => query.whereNull(key));
3649
+ }
3650
+ /**
3651
+ * Adds a not-null check for a key.
3652
+ *
3653
+ * @param key
3654
+ * @returns
3655
+ */
3656
+ whereNotNull(key) {
3657
+ return this.constrain((query) => query.whereNotNull(key));
3658
+ }
3659
+ /**
3660
+ * Adds a between range clause for a key.
3661
+ *
3662
+ * @param key
3663
+ * @param range
3664
+ * @returns
3665
+ */
3666
+ whereBetween(key, range) {
3667
+ return this.constrain((query) => query.whereBetween(key, range));
3668
+ }
3669
+ /**
3670
+ * Adds a date-only equality clause for a date-like key.
3671
+ *
3672
+ * @param key
3673
+ * @param value
3674
+ * @returns
3675
+ */
3676
+ whereDate(key, value) {
3677
+ return this.constrain((query) => query.whereDate(key, value));
3678
+ }
3679
+ whereMonth(key, month, year) {
3680
+ return this.constrain((query) => query.whereMonth(key, month, year));
3681
+ }
3682
+ whereYear(key, year) {
3683
+ return this.constrain((query) => query.whereYear(key, year));
3684
+ }
3685
+ /**
3556
3686
  * Add a strongly-typed where key clause to the relationship query.
3557
3687
  *
3558
3688
  * @param key
@@ -3563,6 +3693,16 @@ var Relation = class {
3563
3693
  return this.constrain((query) => query.whereKey(key, value));
3564
3694
  }
3565
3695
  /**
3696
+ * Adds a strongly-typed inequality where clause for a single attribute key.
3697
+ *
3698
+ * @param key
3699
+ * @param value
3700
+ * @returns
3701
+ */
3702
+ whereKeyNot(key, value) {
3703
+ return this.constrain((query) => query.whereKeyNot(key, value));
3704
+ }
3705
+ /**
3566
3706
  * Add a strongly-typed where in clause to the relationship query.
3567
3707
  *
3568
3708
  * @param key
@@ -3573,6 +3713,36 @@ var Relation = class {
3573
3713
  return this.constrain((query) => query.whereIn(key, values));
3574
3714
  }
3575
3715
  /**
3716
+ * Adds a strongly-typed OR IN where clause for a single attribute key.
3717
+ *
3718
+ * @param key
3719
+ * @param values
3720
+ * @returns
3721
+ */
3722
+ orWhereIn(key, values) {
3723
+ return this.constrain((query) => query.orWhereIn(key, values));
3724
+ }
3725
+ /**
3726
+ * Adds a strongly-typed NOT IN where clause for a single attribute key.
3727
+ *
3728
+ * @param key
3729
+ * @param values
3730
+ * @returns
3731
+ */
3732
+ whereNotIn(key, values) {
3733
+ return this.constrain((query) => query.whereNotIn(key, values));
3734
+ }
3735
+ /**
3736
+ * Adds a strongly-typed OR NOT IN where clause for a single attribute key.
3737
+ *
3738
+ * @param key
3739
+ * @param values
3740
+ * @returns
3741
+ */
3742
+ orWhereNotIn(key, values) {
3743
+ return this.constrain((query) => query.orWhereNotIn(key, values));
3744
+ }
3745
+ /**
3576
3746
  * Add a string contains clause to the relationship query.
3577
3747
  *
3578
3748
  * @param key
@@ -3612,6 +3782,42 @@ var Relation = class {
3612
3782
  return this.constrain((query) => query.orderBy(orderBy));
3613
3783
  }
3614
3784
  /**
3785
+ * Puts the query results in random order.
3786
+ *
3787
+ * @returns
3788
+ */
3789
+ inRandomOrder() {
3790
+ return this.constrain((query) => query.inRandomOrder());
3791
+ }
3792
+ /**
3793
+ * Removes existing order clauses and optionally applies a new one.
3794
+ *
3795
+ * @param column
3796
+ * @param direction
3797
+ * @returns
3798
+ */
3799
+ reorder(column, direction = "asc") {
3800
+ return this.constrain((query) => query.reorder(column, direction));
3801
+ }
3802
+ /**
3803
+ * Adds an orderBy descending clause for a timestamp-like column.
3804
+ *
3805
+ * @param column
3806
+ * @returns
3807
+ */
3808
+ latest(column = "createdAt") {
3809
+ return this.constrain((query) => query.latest(column));
3810
+ }
3811
+ /**
3812
+ * Adds an orderBy ascending clause for a timestamp-like column.
3813
+ *
3814
+ * @param column
3815
+ * @returns
3816
+ */
3817
+ oldest(column = "createdAt") {
3818
+ return this.constrain((query) => query.oldest(column));
3819
+ }
3820
+ /**
3615
3821
  * Add an include clause to the relationship query.
3616
3822
  *
3617
3823
  * @param include
@@ -3638,6 +3844,9 @@ var Relation = class {
3638
3844
  select(select) {
3639
3845
  return this.constrain((query) => query.select(select));
3640
3846
  }
3847
+ addSelect(select) {
3848
+ return this.constrain((query) => query.addSelect(select));
3849
+ }
3641
3850
  /**
3642
3851
  * Add a skip clause to the relationship query.
3643
3852
  *
@@ -3647,6 +3856,9 @@ var Relation = class {
3647
3856
  skip(skip) {
3648
3857
  return this.constrain((query) => query.skip(skip));
3649
3858
  }
3859
+ offset(value) {
3860
+ return this.constrain((query) => query.offset(value));
3861
+ }
3650
3862
  /**
3651
3863
  * Add a take clause to the relationship query.
3652
3864
  *
@@ -3657,6 +3869,45 @@ var Relation = class {
3657
3869
  return this.constrain((query) => query.take(take));
3658
3870
  }
3659
3871
  /**
3872
+ * Alias for take.
3873
+ *
3874
+ * @param value
3875
+ * @returns
3876
+ */
3877
+ limit(value) {
3878
+ return this.constrain((query) => query.limit(value));
3879
+ }
3880
+ /**
3881
+ * Sets offset/limit for a 1-based page.
3882
+ *
3883
+ * @param page
3884
+ * @param perPage
3885
+ * @returns
3886
+ */
3887
+ forPage(page, perPage = 15) {
3888
+ return this.constrain((query) => query.forPage(page, perPage));
3889
+ }
3890
+ /**
3891
+ * Adds a raw where clause when supported by the adapter.
3892
+ *
3893
+ * @param sql
3894
+ * @param bindings
3895
+ * @returns
3896
+ */
3897
+ whereRaw(sql, bindings = []) {
3898
+ return this.constrain((query) => query.whereRaw(sql, bindings));
3899
+ }
3900
+ /**
3901
+ * Adds a raw OR where clause when supported by the adapter.
3902
+ *
3903
+ * @param sql
3904
+ * @param bindings
3905
+ * @returns
3906
+ */
3907
+ orWhereRaw(sql, bindings = []) {
3908
+ return this.constrain((query) => query.orWhereRaw(sql, bindings));
3909
+ }
3910
+ /**
3660
3911
  * Include soft-deleted records in the relationship query.
3661
3912
  *
3662
3913
  * @returns
@@ -5034,6 +5285,78 @@ var MorphToManyRelation = class extends Relation {
5034
5285
  }
5035
5286
  };
5036
5287
 
5288
+ //#endregion
5289
+ //#region src/relationship/MorphToRelation.ts
5290
+ /**
5291
+ * Defines the inverse side of a polymorphic one-to-one or one-to-many relationship.
5292
+ *
5293
+ * Related models are resolved from ArkORM's runtime model registry using the value
5294
+ * stored in the morph type column.
5295
+ *
5296
+ * @author Legacy (3m1n3nc3)
5297
+ * @since 2.6.0
5298
+ */
5299
+ var MorphToRelation = class extends Relation {
5300
+ constructor(parent, morphName, morphTypeColumn, morphIdColumn, ownerKey, relatedModel) {
5301
+ super();
5302
+ this.parent = parent;
5303
+ this.morphName = morphName;
5304
+ this.morphTypeColumn = morphTypeColumn;
5305
+ this.morphIdColumn = morphIdColumn;
5306
+ this.ownerKey = ownerKey;
5307
+ this.relatedModel = relatedModel;
5308
+ }
5309
+ get related() {
5310
+ return this.resolveRelatedModel();
5311
+ }
5312
+ /**
5313
+ * Build the relationship query.
5314
+ *
5315
+ * @returns
5316
+ */
5317
+ async getQuery() {
5318
+ await awaitConfiguredModelsRegistration();
5319
+ const related = this.resolveRelatedModel();
5320
+ const resolvedOwnerKey = this.ownerKey ?? related.getPrimaryKey();
5321
+ const morphId = this.parent.getAttribute(this.morphIdColumn);
5322
+ return this.applyConstraint(related.query().where({ [resolvedOwnerKey]: morphId }));
5323
+ }
5324
+ getMetadata() {
5325
+ return {
5326
+ type: "morphTo",
5327
+ morphName: this.morphName,
5328
+ morphIdColumn: this.morphIdColumn,
5329
+ morphTypeColumn: this.morphTypeColumn,
5330
+ ownerKey: this.ownerKey
5331
+ };
5332
+ }
5333
+ /**
5334
+ * Fetch the polymorphic parent model.
5335
+ *
5336
+ * @returns
5337
+ */
5338
+ async getResults() {
5339
+ const morphType = this.parent.getAttribute(this.morphTypeColumn);
5340
+ const morphId = this.parent.getAttribute(this.morphIdColumn);
5341
+ if (morphType == null || morphId == null) return null;
5342
+ return await (await this.getQuery()).first();
5343
+ }
5344
+ resolveRelatedModel() {
5345
+ const morphType = this.parent.getAttribute(this.morphTypeColumn);
5346
+ if (typeof morphType !== "string" || morphType.trim().length === 0) throw new RelationResolutionException(`Morph type column [${this.morphTypeColumn}] does not contain a model name.`, {
5347
+ operation: "morphTo",
5348
+ relation: this.morphName
5349
+ });
5350
+ const related = this.relatedModel?.name === morphType ? this.relatedModel : getRegisteredModels().find((model) => model.name === morphType);
5351
+ if (!related) throw new RelationResolutionException(`Morph model [${morphType}] is not registered. Register it with Arkorm.registerModels().`, {
5352
+ operation: "morphTo",
5353
+ model: morphType,
5354
+ relation: this.morphName
5355
+ });
5356
+ return related;
5357
+ }
5358
+ };
5359
+
5037
5360
  //#endregion
5038
5361
  Object.defineProperty(exports, 'ArkormCollection', {
5039
5362
  enumerable: true,
@@ -5119,6 +5442,12 @@ Object.defineProperty(exports, 'MorphToManyRelation', {
5119
5442
  return MorphToManyRelation;
5120
5443
  }
5121
5444
  });
5445
+ Object.defineProperty(exports, 'MorphToRelation', {
5446
+ enumerable: true,
5447
+ get: function () {
5448
+ return MorphToRelation;
5449
+ }
5450
+ });
5122
5451
  Object.defineProperty(exports, 'PRISMA_ENUM_MEMBER_REGEX', {
5123
5452
  enumerable: true,
5124
5453
  get: function () {
@@ -5269,6 +5598,12 @@ Object.defineProperty(exports, 'applyOperationsToPrismaSchema', {
5269
5598
  return applyOperationsToPrismaSchema;
5270
5599
  }
5271
5600
  });
5601
+ Object.defineProperty(exports, 'awaitConfiguredModelsRegistration', {
5602
+ enumerable: true,
5603
+ get: function () {
5604
+ return awaitConfiguredModelsRegistration;
5605
+ }
5606
+ });
5272
5607
  Object.defineProperty(exports, 'bindAdapterToModels', {
5273
5608
  enumerable: true,
5274
5609
  get: function () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkormx",
3
- "version": "2.5.2",
3
+ "version": "2.5.4",
4
4
  "description": "Modern TypeScript-first ORM for Node.js.",
5
5
  "keywords": [
6
6
  "orm",