arkormx 0.2.9 → 0.2.11

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/cli.mjs CHANGED
@@ -1135,6 +1135,7 @@ let runtimeConfigLoaded = false;
1135
1135
  let runtimeConfigLoadingPromise;
1136
1136
  let runtimeClientResolver;
1137
1137
  let runtimePaginationURLDriverFactory;
1138
+ let runtimePaginationCurrentPageResolver;
1138
1139
  const mergePathConfig = (paths) => {
1139
1140
  const defaults = baseConfig.paths ?? {};
1140
1141
  const current = userConfig.paths ?? {};
@@ -1175,6 +1176,7 @@ const configureArkormRuntime = (prisma, options = {}) => {
1175
1176
  Object.assign(userConfig, { ...nextConfig });
1176
1177
  runtimeClientResolver = prisma;
1177
1178
  runtimePaginationURLDriverFactory = nextConfig.pagination?.urlDriver;
1179
+ runtimePaginationCurrentPageResolver = nextConfig.pagination?.resolveCurrentPage;
1178
1180
  };
1179
1181
  /**
1180
1182
  * Resolve and apply the ArkORM configuration from an imported module.
package/dist/index.cjs CHANGED
@@ -41,6 +41,24 @@ let node_crypto = require("node:crypto");
41
41
  let node_url = require("node:url");
42
42
  let _h3ravel_collect_js = require("@h3ravel/collect.js");
43
43
 
44
+ //#region src/Attribute.ts
45
+ var Attribute = class Attribute {
46
+ get;
47
+ set;
48
+ constructor(options = {}) {
49
+ this.get = options.get;
50
+ this.set = options.set;
51
+ }
52
+ static make(options) {
53
+ return new Attribute(options);
54
+ }
55
+ static isAttribute(value) {
56
+ if (!value || typeof value !== "object") return false;
57
+ return value instanceof Attribute;
58
+ }
59
+ };
60
+
61
+ //#endregion
44
62
  //#region src/casts.ts
45
63
  const builtinCasts = {
46
64
  string: {
@@ -1257,6 +1275,7 @@ let runtimeConfigLoaded = false;
1257
1275
  let runtimeConfigLoadingPromise;
1258
1276
  let runtimeClientResolver;
1259
1277
  let runtimePaginationURLDriverFactory;
1278
+ let runtimePaginationCurrentPageResolver;
1260
1279
  const mergePathConfig = (paths) => {
1261
1280
  const defaults = baseConfig.paths ?? {};
1262
1281
  const current = userConfig.paths ?? {};
@@ -1306,6 +1325,7 @@ const configureArkormRuntime = (prisma, options = {}) => {
1306
1325
  Object.assign(userConfig, { ...nextConfig });
1307
1326
  runtimeClientResolver = prisma;
1308
1327
  runtimePaginationURLDriverFactory = nextConfig.pagination?.urlDriver;
1328
+ runtimePaginationCurrentPageResolver = nextConfig.pagination?.resolveCurrentPage;
1309
1329
  };
1310
1330
  /**
1311
1331
  * Reset the ArkORM runtime configuration.
@@ -1320,6 +1340,7 @@ const resetArkormRuntimeForTests = () => {
1320
1340
  runtimeConfigLoadingPromise = void 0;
1321
1341
  runtimeClientResolver = void 0;
1322
1342
  runtimePaginationURLDriverFactory = void 0;
1343
+ runtimePaginationCurrentPageResolver = void 0;
1323
1344
  };
1324
1345
  /**
1325
1346
  * Resolve a Prisma client instance from the provided resolver, which can be either
@@ -1435,6 +1456,15 @@ const getRuntimePaginationURLDriverFactory = () => {
1435
1456
  return runtimePaginationURLDriverFactory;
1436
1457
  };
1437
1458
  /**
1459
+ * Get the configured current-page resolver from runtime config.
1460
+ *
1461
+ * @returns
1462
+ */
1463
+ const getRuntimePaginationCurrentPageResolver = () => {
1464
+ if (!runtimeConfigLoaded) loadRuntimeConfigSync();
1465
+ return runtimePaginationCurrentPageResolver;
1466
+ };
1467
+ /**
1438
1468
  * Check if a given value is a Prisma delegate-like object
1439
1469
  * by verifying the presence of common delegate methods.
1440
1470
  *
@@ -3487,6 +3517,13 @@ var QueryBuilder = class QueryBuilder {
3487
3517
  this.delegate = delegate;
3488
3518
  this.model = model;
3489
3519
  }
3520
+ resolvePaginationPage(page, options) {
3521
+ if (typeof page !== "undefined") return Number.isFinite(page) ? Math.max(1, page) : 1;
3522
+ const pageName = options.pageName ?? "page";
3523
+ const resolvedPage = getRuntimePaginationCurrentPageResolver()?.(pageName, options);
3524
+ if (typeof resolvedPage !== "number" || !Number.isFinite(resolvedPage)) return 1;
3525
+ return Math.max(1, resolvedPage);
3526
+ }
3490
3527
  /**
3491
3528
  * Adds a where clause to the query. Multiple calls to where will combine
3492
3529
  * the clauses with AND logic.
@@ -4605,15 +4642,14 @@ var QueryBuilder = class QueryBuilder {
4605
4642
  * @param options
4606
4643
  * @returns
4607
4644
  */
4608
- async paginate(page = 1, perPage = 15, options = {}) {
4645
+ async paginate(perPage = 15, page = void 0, options = {}) {
4646
+ const currentPage = this.resolvePaginationPage(page, options);
4609
4647
  if (this.hasRelationFilters() || this.hasRelationAggregates()) {
4610
- const currentPage = Math.max(1, page);
4611
4648
  const pageSize = Math.max(1, perPage);
4612
4649
  const rows = (await this.get()).all();
4613
4650
  const start = (currentPage - 1) * pageSize;
4614
4651
  return new LengthAwarePaginator(new ArkormCollection(rows.slice(start, start + pageSize)), rows.length, pageSize, currentPage, options);
4615
4652
  }
4616
- const currentPage = Math.max(1, page);
4617
4653
  const pageSize = Math.max(1, perPage);
4618
4654
  const total = await this.count();
4619
4655
  return new LengthAwarePaginator(await this.clone().skip((currentPage - 1) * pageSize).take(pageSize).get(), total, pageSize, currentPage, options);
@@ -4625,9 +4661,9 @@ var QueryBuilder = class QueryBuilder {
4625
4661
  * @param page
4626
4662
  * @returns
4627
4663
  */
4628
- async simplePaginate(perPage = 15, page = 1, options = {}) {
4664
+ async simplePaginate(perPage = 15, page = void 0, options = {}) {
4665
+ const currentPage = this.resolvePaginationPage(page, options);
4629
4666
  if (this.hasRelationFilters() || this.hasRelationAggregates()) {
4630
- const currentPage = Math.max(1, page);
4631
4667
  const pageSize = Math.max(1, perPage);
4632
4668
  const rows = (await this.get()).all();
4633
4669
  const start = (currentPage - 1) * pageSize;
@@ -4635,7 +4671,6 @@ var QueryBuilder = class QueryBuilder {
4635
4671
  const hasMorePages = start + pageSize < rows.length;
4636
4672
  return new Paginator(new ArkormCollection(pageRows), pageSize, currentPage, hasMorePages, options);
4637
4673
  }
4638
- const currentPage = Math.max(1, page);
4639
4674
  const pageSize = Math.max(1, perPage);
4640
4675
  const items = await this.clone().skip((currentPage - 1) * pageSize).take(pageSize + 1).get();
4641
4676
  const hasMorePages = items.all().length > pageSize;
@@ -4914,11 +4949,15 @@ var Model = class Model {
4914
4949
  this.fill(attributes);
4915
4950
  return new Proxy(this, {
4916
4951
  get: (target, key, receiver) => {
4917
- if (typeof key !== "string" || key in target) return Reflect.get(target, key, receiver);
4952
+ if (typeof key !== "string") return Reflect.get(target, key, receiver);
4953
+ const attributeMutator = target.resolveAttributeMutator(key);
4954
+ if (key in target && !attributeMutator) return Reflect.get(target, key, receiver);
4918
4955
  return target.getAttribute(key);
4919
4956
  },
4920
4957
  set: (target, key, value, receiver) => {
4921
- if (typeof key !== "string" || key in target) return Reflect.set(target, key, value, receiver);
4958
+ if (typeof key !== "string") return Reflect.set(target, key, value, receiver);
4959
+ const attributeMutator = target.resolveAttributeMutator(key);
4960
+ if (key in target && !attributeMutator) return Reflect.set(target, key, value, receiver);
4922
4961
  target.setAttribute(key, value);
4923
4962
  return true;
4924
4963
  }
@@ -5107,18 +5146,22 @@ var Model = class Model {
5107
5146
  return this;
5108
5147
  }
5109
5148
  getAttribute(key) {
5149
+ const attributeMutator = this.resolveAttributeMutator(key);
5110
5150
  const mutator = this.resolveGetMutator(key);
5111
5151
  const cast = this.casts[key];
5112
5152
  let value = this.attributes[key];
5113
5153
  if (cast) value = resolveCast(cast).get(value);
5154
+ if (attributeMutator?.get) return attributeMutator.get.call(this, value);
5114
5155
  if (mutator) return mutator.call(this, value);
5115
5156
  return value;
5116
5157
  }
5117
5158
  setAttribute(key, value) {
5159
+ const attributeMutator = this.resolveAttributeMutator(key);
5118
5160
  const mutator = this.resolveSetMutator(key);
5119
5161
  const cast = this.casts[key];
5120
5162
  let resolved = value;
5121
- if (mutator) resolved = mutator.call(this, resolved);
5163
+ if (attributeMutator?.set) resolved = attributeMutator.set.call(this, resolved);
5164
+ else if (mutator) resolved = mutator.call(this, resolved);
5122
5165
  if (cast) resolved = resolveCast(cast).set(resolved);
5123
5166
  this.attributes[key] = resolved;
5124
5167
  return this;
@@ -5386,6 +5429,24 @@ var Model = class Model {
5386
5429
  return typeof method === "function" ? method : null;
5387
5430
  }
5388
5431
  /**
5432
+ * Resolve an Attribute object mutator method for a given key, if it exists.
5433
+ *
5434
+ * @param key
5435
+ * @returns
5436
+ */
5437
+ resolveAttributeMutator(key) {
5438
+ if (key === "constructor") return null;
5439
+ const methodName = `${(0, _h3ravel_support.str)(key).camel()}`;
5440
+ const prototype = Object.getPrototypeOf(this);
5441
+ if (!prototype) return null;
5442
+ const method = prototype[methodName];
5443
+ if (typeof method !== "function") return null;
5444
+ if (method === Model.prototype[methodName]) return null;
5445
+ const resolved = method.call(this);
5446
+ if (Attribute.isAttribute(resolved)) return resolved;
5447
+ return null;
5448
+ }
5449
+ /**
5389
5450
  * Resolve a set mutator method for a given attribute key, if it exists.
5390
5451
  *
5391
5452
  * @param key
@@ -5439,6 +5500,7 @@ var Model = class Model {
5439
5500
  //#endregion
5440
5501
  exports.ArkormCollection = ArkormCollection;
5441
5502
  exports.ArkormException = ArkormException;
5503
+ exports.Attribute = Attribute;
5442
5504
  exports.CliApp = CliApp;
5443
5505
  exports.ForeignKeyBuilder = ForeignKeyBuilder;
5444
5506
  exports.InitCommand = InitCommand;
@@ -5501,6 +5563,7 @@ exports.getDefaultStubsPath = getDefaultStubsPath;
5501
5563
  exports.getLastMigrationRun = getLastMigrationRun;
5502
5564
  exports.getLatestAppliedMigrations = getLatestAppliedMigrations;
5503
5565
  exports.getMigrationPlan = getMigrationPlan;
5566
+ exports.getRuntimePaginationCurrentPageResolver = getRuntimePaginationCurrentPageResolver;
5504
5567
  exports.getRuntimePaginationURLDriverFactory = getRuntimePaginationURLDriverFactory;
5505
5568
  exports.getRuntimePrismaClient = getRuntimePrismaClient;
5506
5569
  exports.getUserConfig = getUserConfig;
package/dist/index.d.cts CHANGED
@@ -2,6 +2,19 @@ import { PrismaClient } from "@prisma/client";
2
2
  import { Collection } from "@h3ravel/collect.js";
3
3
  import { Command } from "@h3ravel/musket";
4
4
 
5
+ //#region src/Attribute.d.ts
6
+ interface AttributeOptions<TGet = unknown, TSet = unknown> {
7
+ get?: (value: unknown) => TGet;
8
+ set?: (value: TSet) => unknown;
9
+ }
10
+ declare class Attribute<TGet = unknown, TSet = unknown> {
11
+ readonly get?: (value: unknown) => TGet;
12
+ readonly set?: (value: TSet) => unknown;
13
+ constructor(options?: AttributeOptions<TGet, TSet>);
14
+ static make<TGet = unknown, TSet = unknown>(options: AttributeOptions<TGet, TSet>): Attribute<TGet, TSet>;
15
+ static isAttribute(value: unknown): value is Attribute;
16
+ }
17
+ //#endregion
5
18
  //#region src/types/factories.d.ts
6
19
  type FactoryAttributes = Record<string, unknown>;
7
20
  interface FactoryModelConstructor<TModel> {
@@ -873,6 +886,13 @@ declare abstract class Model<TSchema extends PrismaDelegateLike | Record<string,
873
886
  * @returns
874
887
  */
875
888
  private resolveGetMutator;
889
+ /**
890
+ * Resolve an Attribute object mutator method for a given key, if it exists.
891
+ *
892
+ * @param key
893
+ * @returns
894
+ */
895
+ private resolveAttributeMutator;
876
896
  /**
877
897
  * Resolve a set mutator method for a given attribute key, if it exists.
878
898
  *
@@ -1019,6 +1039,7 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
1019
1039
  * @param model
1020
1040
  */
1021
1041
  constructor(delegate: TDelegate, model: ModelStatic<TModel, TDelegate>);
1042
+ private resolvePaginationPage;
1022
1043
  /**
1023
1044
  * Adds a where clause to the query. Multiple calls to where will combine
1024
1045
  * the clauses with AND logic.
@@ -1680,7 +1701,7 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
1680
1701
  * @param options
1681
1702
  * @returns
1682
1703
  */
1683
- paginate(page?: number, perPage?: number, options?: PaginationOptions): Promise<LengthAwarePaginator<TModel>>;
1704
+ paginate(perPage?: number, page?: number | undefined, options?: PaginationOptions): Promise<LengthAwarePaginator<TModel>>;
1684
1705
  /**
1685
1706
  * Paginates results without calculating total row count.
1686
1707
  *
@@ -1688,7 +1709,7 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
1688
1709
  * @param page
1689
1710
  * @returns
1690
1711
  */
1691
- simplePaginate(perPage?: number, page?: number, options?: PaginationOptions): Promise<Paginator<TModel>>;
1712
+ simplePaginate(perPage?: number, page?: number | undefined, options?: PaginationOptions): Promise<Paginator<TModel>>;
1692
1713
  /**
1693
1714
  * Creates a clone of the current query builder instance with the same state.
1694
1715
  *
@@ -1779,6 +1800,7 @@ interface ArkormConfig {
1779
1800
  */
1780
1801
  pagination?: {
1781
1802
  urlDriver?: PaginationURLDriverFactory;
1803
+ resolveCurrentPage?: PaginationCurrentPageResolver;
1782
1804
  };
1783
1805
  /**
1784
1806
  * @property paths Optional custom paths for various generated files.
@@ -1846,6 +1868,7 @@ interface PaginationOptions {
1846
1868
  fragment?: string;
1847
1869
  pageName?: string;
1848
1870
  }
1871
+ type PaginationCurrentPageResolver = (pageName: string, options: PaginationOptions) => number | undefined;
1849
1872
  interface PaginationURLDriver {
1850
1873
  getPageName: () => string;
1851
1874
  url: (page: number) => string;
@@ -3108,6 +3131,12 @@ declare const getRuntimePrismaClient: () => PrismaClientLike | undefined;
3108
3131
  * @returns
3109
3132
  */
3110
3133
  declare const getRuntimePaginationURLDriverFactory: () => PaginationURLDriverFactory | undefined;
3134
+ /**
3135
+ * Get the configured current-page resolver from runtime config.
3136
+ *
3137
+ * @returns
3138
+ */
3139
+ declare const getRuntimePaginationCurrentPageResolver: () => PaginationCurrentPageResolver | undefined;
3111
3140
  /**
3112
3141
  * Check if a given value is a Prisma delegate-like object
3113
3142
  * by verifying the presence of common delegate methods.
@@ -3162,4 +3191,4 @@ declare class URLDriver {
3162
3191
  url(page: number): string;
3163
3192
  }
3164
3193
  //#endregion
3165
- export { ArkormCollection, ArkormException, CliApp, ForeignKeyBuilder, InitCommand, InlineFactory, LengthAwarePaginator, MIGRATION_BRAND, MakeFactoryCommand, MakeMigrationCommand, MakeModelCommand, MakeSeederCommand, MigrateCommand, MigrateRollbackCommand, Migration, MigrationHistoryCommand, Model, ModelFactory, ModelNotFoundException, ModelsSyncCommand, PRISMA_MODEL_REGEX, Paginator, PrismaDelegateMap, QueryBuilder, SEEDER_BRAND, SchemaBuilder, SeedCommand, Seeder, SeederCallArgument, SeederConstructor, SeederInput, TableBuilder, URLDriver, applyAlterTableOperation, applyCreateTableOperation, applyDropTableOperation, applyMigrationRollbackToPrismaSchema, applyMigrationToPrismaSchema, applyOperationsToPrismaSchema, buildFieldLine, buildIndexLine, buildInverseRelationLine, buildMigrationIdentity, buildMigrationRunId, buildMigrationSource, buildModelBlock, buildRelationLine, computeMigrationChecksum, configureArkormRuntime, createMigrationTimestamp, createPrismaAdapter, createPrismaDelegateMap, defineConfig, defineFactory, deriveCollectionFieldName, deriveInverseRelationAlias, deriveRelationFieldName, ensureArkormConfigLoading, escapeRegex, findAppliedMigration, findModelBlock, formatDefaultValue, formatRelationAction, generateMigrationFile, getDefaultStubsPath, getLastMigrationRun, getLatestAppliedMigrations, getMigrationPlan, getRuntimePaginationURLDriverFactory, getRuntimePrismaClient, getUserConfig, inferDelegateName, isDelegateLike, isMigrationApplied, loadArkormConfig, markMigrationApplied, markMigrationRun, pad, readAppliedMigrationsState, removeAppliedMigration, resetArkormRuntimeForTests, resolveCast, resolveMigrationClassName, resolveMigrationStateFilePath, resolvePrismaType, runMigrationWithPrisma, runPrismaCommand, toMigrationFileSlug, toModelName, writeAppliedMigrationsState };
3194
+ export { ArkormCollection, ArkormException, Attribute, AttributeOptions, CliApp, ForeignKeyBuilder, InitCommand, InlineFactory, LengthAwarePaginator, MIGRATION_BRAND, MakeFactoryCommand, MakeMigrationCommand, MakeModelCommand, MakeSeederCommand, MigrateCommand, MigrateRollbackCommand, Migration, MigrationHistoryCommand, Model, ModelFactory, ModelNotFoundException, ModelsSyncCommand, PRISMA_MODEL_REGEX, Paginator, PrismaDelegateMap, QueryBuilder, SEEDER_BRAND, SchemaBuilder, SeedCommand, Seeder, SeederCallArgument, SeederConstructor, SeederInput, TableBuilder, URLDriver, applyAlterTableOperation, applyCreateTableOperation, applyDropTableOperation, applyMigrationRollbackToPrismaSchema, applyMigrationToPrismaSchema, applyOperationsToPrismaSchema, buildFieldLine, buildIndexLine, buildInverseRelationLine, buildMigrationIdentity, buildMigrationRunId, buildMigrationSource, buildModelBlock, buildRelationLine, computeMigrationChecksum, configureArkormRuntime, createMigrationTimestamp, createPrismaAdapter, createPrismaDelegateMap, defineConfig, defineFactory, deriveCollectionFieldName, deriveInverseRelationAlias, deriveRelationFieldName, ensureArkormConfigLoading, escapeRegex, findAppliedMigration, findModelBlock, formatDefaultValue, formatRelationAction, generateMigrationFile, getDefaultStubsPath, getLastMigrationRun, getLatestAppliedMigrations, getMigrationPlan, getRuntimePaginationCurrentPageResolver, getRuntimePaginationURLDriverFactory, getRuntimePrismaClient, getUserConfig, inferDelegateName, isDelegateLike, isMigrationApplied, loadArkormConfig, markMigrationApplied, markMigrationRun, pad, readAppliedMigrationsState, removeAppliedMigration, resetArkormRuntimeForTests, resolveCast, resolveMigrationClassName, resolveMigrationStateFilePath, resolvePrismaType, runMigrationWithPrisma, runPrismaCommand, toMigrationFileSlug, toModelName, writeAppliedMigrationsState };
package/dist/index.d.mts CHANGED
@@ -2,6 +2,19 @@ import { Command } from "@h3ravel/musket";
2
2
  import { Collection } from "@h3ravel/collect.js";
3
3
  import { PrismaClient } from "@prisma/client";
4
4
 
5
+ //#region src/Attribute.d.ts
6
+ interface AttributeOptions<TGet = unknown, TSet = unknown> {
7
+ get?: (value: unknown) => TGet;
8
+ set?: (value: TSet) => unknown;
9
+ }
10
+ declare class Attribute<TGet = unknown, TSet = unknown> {
11
+ readonly get?: (value: unknown) => TGet;
12
+ readonly set?: (value: TSet) => unknown;
13
+ constructor(options?: AttributeOptions<TGet, TSet>);
14
+ static make<TGet = unknown, TSet = unknown>(options: AttributeOptions<TGet, TSet>): Attribute<TGet, TSet>;
15
+ static isAttribute(value: unknown): value is Attribute;
16
+ }
17
+ //#endregion
5
18
  //#region src/types/factories.d.ts
6
19
  type FactoryAttributes = Record<string, unknown>;
7
20
  interface FactoryModelConstructor<TModel> {
@@ -873,6 +886,13 @@ declare abstract class Model<TSchema extends PrismaDelegateLike | Record<string,
873
886
  * @returns
874
887
  */
875
888
  private resolveGetMutator;
889
+ /**
890
+ * Resolve an Attribute object mutator method for a given key, if it exists.
891
+ *
892
+ * @param key
893
+ * @returns
894
+ */
895
+ private resolveAttributeMutator;
876
896
  /**
877
897
  * Resolve a set mutator method for a given attribute key, if it exists.
878
898
  *
@@ -1019,6 +1039,7 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
1019
1039
  * @param model
1020
1040
  */
1021
1041
  constructor(delegate: TDelegate, model: ModelStatic<TModel, TDelegate>);
1042
+ private resolvePaginationPage;
1022
1043
  /**
1023
1044
  * Adds a where clause to the query. Multiple calls to where will combine
1024
1045
  * the clauses with AND logic.
@@ -1680,7 +1701,7 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
1680
1701
  * @param options
1681
1702
  * @returns
1682
1703
  */
1683
- paginate(page?: number, perPage?: number, options?: PaginationOptions): Promise<LengthAwarePaginator<TModel>>;
1704
+ paginate(perPage?: number, page?: number | undefined, options?: PaginationOptions): Promise<LengthAwarePaginator<TModel>>;
1684
1705
  /**
1685
1706
  * Paginates results without calculating total row count.
1686
1707
  *
@@ -1688,7 +1709,7 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
1688
1709
  * @param page
1689
1710
  * @returns
1690
1711
  */
1691
- simplePaginate(perPage?: number, page?: number, options?: PaginationOptions): Promise<Paginator<TModel>>;
1712
+ simplePaginate(perPage?: number, page?: number | undefined, options?: PaginationOptions): Promise<Paginator<TModel>>;
1692
1713
  /**
1693
1714
  * Creates a clone of the current query builder instance with the same state.
1694
1715
  *
@@ -1779,6 +1800,7 @@ interface ArkormConfig {
1779
1800
  */
1780
1801
  pagination?: {
1781
1802
  urlDriver?: PaginationURLDriverFactory;
1803
+ resolveCurrentPage?: PaginationCurrentPageResolver;
1782
1804
  };
1783
1805
  /**
1784
1806
  * @property paths Optional custom paths for various generated files.
@@ -1846,6 +1868,7 @@ interface PaginationOptions {
1846
1868
  fragment?: string;
1847
1869
  pageName?: string;
1848
1870
  }
1871
+ type PaginationCurrentPageResolver = (pageName: string, options: PaginationOptions) => number | undefined;
1849
1872
  interface PaginationURLDriver {
1850
1873
  getPageName: () => string;
1851
1874
  url: (page: number) => string;
@@ -3108,6 +3131,12 @@ declare const getRuntimePrismaClient: () => PrismaClientLike | undefined;
3108
3131
  * @returns
3109
3132
  */
3110
3133
  declare const getRuntimePaginationURLDriverFactory: () => PaginationURLDriverFactory | undefined;
3134
+ /**
3135
+ * Get the configured current-page resolver from runtime config.
3136
+ *
3137
+ * @returns
3138
+ */
3139
+ declare const getRuntimePaginationCurrentPageResolver: () => PaginationCurrentPageResolver | undefined;
3111
3140
  /**
3112
3141
  * Check if a given value is a Prisma delegate-like object
3113
3142
  * by verifying the presence of common delegate methods.
@@ -3162,4 +3191,4 @@ declare class URLDriver {
3162
3191
  url(page: number): string;
3163
3192
  }
3164
3193
  //#endregion
3165
- export { ArkormCollection, ArkormException, CliApp, ForeignKeyBuilder, InitCommand, InlineFactory, LengthAwarePaginator, MIGRATION_BRAND, MakeFactoryCommand, MakeMigrationCommand, MakeModelCommand, MakeSeederCommand, MigrateCommand, MigrateRollbackCommand, Migration, MigrationHistoryCommand, Model, ModelFactory, ModelNotFoundException, ModelsSyncCommand, PRISMA_MODEL_REGEX, Paginator, PrismaDelegateMap, QueryBuilder, SEEDER_BRAND, SchemaBuilder, SeedCommand, Seeder, SeederCallArgument, SeederConstructor, SeederInput, TableBuilder, URLDriver, applyAlterTableOperation, applyCreateTableOperation, applyDropTableOperation, applyMigrationRollbackToPrismaSchema, applyMigrationToPrismaSchema, applyOperationsToPrismaSchema, buildFieldLine, buildIndexLine, buildInverseRelationLine, buildMigrationIdentity, buildMigrationRunId, buildMigrationSource, buildModelBlock, buildRelationLine, computeMigrationChecksum, configureArkormRuntime, createMigrationTimestamp, createPrismaAdapter, createPrismaDelegateMap, defineConfig, defineFactory, deriveCollectionFieldName, deriveInverseRelationAlias, deriveRelationFieldName, ensureArkormConfigLoading, escapeRegex, findAppliedMigration, findModelBlock, formatDefaultValue, formatRelationAction, generateMigrationFile, getDefaultStubsPath, getLastMigrationRun, getLatestAppliedMigrations, getMigrationPlan, getRuntimePaginationURLDriverFactory, getRuntimePrismaClient, getUserConfig, inferDelegateName, isDelegateLike, isMigrationApplied, loadArkormConfig, markMigrationApplied, markMigrationRun, pad, readAppliedMigrationsState, removeAppliedMigration, resetArkormRuntimeForTests, resolveCast, resolveMigrationClassName, resolveMigrationStateFilePath, resolvePrismaType, runMigrationWithPrisma, runPrismaCommand, toMigrationFileSlug, toModelName, writeAppliedMigrationsState };
3194
+ export { ArkormCollection, ArkormException, Attribute, AttributeOptions, CliApp, ForeignKeyBuilder, InitCommand, InlineFactory, LengthAwarePaginator, MIGRATION_BRAND, MakeFactoryCommand, MakeMigrationCommand, MakeModelCommand, MakeSeederCommand, MigrateCommand, MigrateRollbackCommand, Migration, MigrationHistoryCommand, Model, ModelFactory, ModelNotFoundException, ModelsSyncCommand, PRISMA_MODEL_REGEX, Paginator, PrismaDelegateMap, QueryBuilder, SEEDER_BRAND, SchemaBuilder, SeedCommand, Seeder, SeederCallArgument, SeederConstructor, SeederInput, TableBuilder, URLDriver, applyAlterTableOperation, applyCreateTableOperation, applyDropTableOperation, applyMigrationRollbackToPrismaSchema, applyMigrationToPrismaSchema, applyOperationsToPrismaSchema, buildFieldLine, buildIndexLine, buildInverseRelationLine, buildMigrationIdentity, buildMigrationRunId, buildMigrationSource, buildModelBlock, buildRelationLine, computeMigrationChecksum, configureArkormRuntime, createMigrationTimestamp, createPrismaAdapter, createPrismaDelegateMap, defineConfig, defineFactory, deriveCollectionFieldName, deriveInverseRelationAlias, deriveRelationFieldName, ensureArkormConfigLoading, escapeRegex, findAppliedMigration, findModelBlock, formatDefaultValue, formatRelationAction, generateMigrationFile, getDefaultStubsPath, getLastMigrationRun, getLatestAppliedMigrations, getMigrationPlan, getRuntimePaginationCurrentPageResolver, getRuntimePaginationURLDriverFactory, getRuntimePrismaClient, getUserConfig, inferDelegateName, isDelegateLike, isMigrationApplied, loadArkormConfig, markMigrationApplied, markMigrationRun, pad, readAppliedMigrationsState, removeAppliedMigration, resetArkormRuntimeForTests, resolveCast, resolveMigrationClassName, resolveMigrationStateFilePath, resolvePrismaType, runMigrationWithPrisma, runPrismaCommand, toMigrationFileSlug, toModelName, writeAppliedMigrationsState };
package/dist/index.mjs CHANGED
@@ -12,6 +12,24 @@ import { createHash } from "node:crypto";
12
12
  import { pathToFileURL as pathToFileURL$1 } from "node:url";
13
13
  import { Collection } from "@h3ravel/collect.js";
14
14
 
15
+ //#region src/Attribute.ts
16
+ var Attribute = class Attribute {
17
+ get;
18
+ set;
19
+ constructor(options = {}) {
20
+ this.get = options.get;
21
+ this.set = options.set;
22
+ }
23
+ static make(options) {
24
+ return new Attribute(options);
25
+ }
26
+ static isAttribute(value) {
27
+ if (!value || typeof value !== "object") return false;
28
+ return value instanceof Attribute;
29
+ }
30
+ };
31
+
32
+ //#endregion
15
33
  //#region src/casts.ts
16
34
  const builtinCasts = {
17
35
  string: {
@@ -1228,6 +1246,7 @@ let runtimeConfigLoaded = false;
1228
1246
  let runtimeConfigLoadingPromise;
1229
1247
  let runtimeClientResolver;
1230
1248
  let runtimePaginationURLDriverFactory;
1249
+ let runtimePaginationCurrentPageResolver;
1231
1250
  const mergePathConfig = (paths) => {
1232
1251
  const defaults = baseConfig.paths ?? {};
1233
1252
  const current = userConfig.paths ?? {};
@@ -1277,6 +1296,7 @@ const configureArkormRuntime = (prisma, options = {}) => {
1277
1296
  Object.assign(userConfig, { ...nextConfig });
1278
1297
  runtimeClientResolver = prisma;
1279
1298
  runtimePaginationURLDriverFactory = nextConfig.pagination?.urlDriver;
1299
+ runtimePaginationCurrentPageResolver = nextConfig.pagination?.resolveCurrentPage;
1280
1300
  };
1281
1301
  /**
1282
1302
  * Reset the ArkORM runtime configuration.
@@ -1291,6 +1311,7 @@ const resetArkormRuntimeForTests = () => {
1291
1311
  runtimeConfigLoadingPromise = void 0;
1292
1312
  runtimeClientResolver = void 0;
1293
1313
  runtimePaginationURLDriverFactory = void 0;
1314
+ runtimePaginationCurrentPageResolver = void 0;
1294
1315
  };
1295
1316
  /**
1296
1317
  * Resolve a Prisma client instance from the provided resolver, which can be either
@@ -1406,6 +1427,15 @@ const getRuntimePaginationURLDriverFactory = () => {
1406
1427
  return runtimePaginationURLDriverFactory;
1407
1428
  };
1408
1429
  /**
1430
+ * Get the configured current-page resolver from runtime config.
1431
+ *
1432
+ * @returns
1433
+ */
1434
+ const getRuntimePaginationCurrentPageResolver = () => {
1435
+ if (!runtimeConfigLoaded) loadRuntimeConfigSync();
1436
+ return runtimePaginationCurrentPageResolver;
1437
+ };
1438
+ /**
1409
1439
  * Check if a given value is a Prisma delegate-like object
1410
1440
  * by verifying the presence of common delegate methods.
1411
1441
  *
@@ -3458,6 +3488,13 @@ var QueryBuilder = class QueryBuilder {
3458
3488
  this.delegate = delegate;
3459
3489
  this.model = model;
3460
3490
  }
3491
+ resolvePaginationPage(page, options) {
3492
+ if (typeof page !== "undefined") return Number.isFinite(page) ? Math.max(1, page) : 1;
3493
+ const pageName = options.pageName ?? "page";
3494
+ const resolvedPage = getRuntimePaginationCurrentPageResolver()?.(pageName, options);
3495
+ if (typeof resolvedPage !== "number" || !Number.isFinite(resolvedPage)) return 1;
3496
+ return Math.max(1, resolvedPage);
3497
+ }
3461
3498
  /**
3462
3499
  * Adds a where clause to the query. Multiple calls to where will combine
3463
3500
  * the clauses with AND logic.
@@ -4576,15 +4613,14 @@ var QueryBuilder = class QueryBuilder {
4576
4613
  * @param options
4577
4614
  * @returns
4578
4615
  */
4579
- async paginate(page = 1, perPage = 15, options = {}) {
4616
+ async paginate(perPage = 15, page = void 0, options = {}) {
4617
+ const currentPage = this.resolvePaginationPage(page, options);
4580
4618
  if (this.hasRelationFilters() || this.hasRelationAggregates()) {
4581
- const currentPage = Math.max(1, page);
4582
4619
  const pageSize = Math.max(1, perPage);
4583
4620
  const rows = (await this.get()).all();
4584
4621
  const start = (currentPage - 1) * pageSize;
4585
4622
  return new LengthAwarePaginator(new ArkormCollection(rows.slice(start, start + pageSize)), rows.length, pageSize, currentPage, options);
4586
4623
  }
4587
- const currentPage = Math.max(1, page);
4588
4624
  const pageSize = Math.max(1, perPage);
4589
4625
  const total = await this.count();
4590
4626
  return new LengthAwarePaginator(await this.clone().skip((currentPage - 1) * pageSize).take(pageSize).get(), total, pageSize, currentPage, options);
@@ -4596,9 +4632,9 @@ var QueryBuilder = class QueryBuilder {
4596
4632
  * @param page
4597
4633
  * @returns
4598
4634
  */
4599
- async simplePaginate(perPage = 15, page = 1, options = {}) {
4635
+ async simplePaginate(perPage = 15, page = void 0, options = {}) {
4636
+ const currentPage = this.resolvePaginationPage(page, options);
4600
4637
  if (this.hasRelationFilters() || this.hasRelationAggregates()) {
4601
- const currentPage = Math.max(1, page);
4602
4638
  const pageSize = Math.max(1, perPage);
4603
4639
  const rows = (await this.get()).all();
4604
4640
  const start = (currentPage - 1) * pageSize;
@@ -4606,7 +4642,6 @@ var QueryBuilder = class QueryBuilder {
4606
4642
  const hasMorePages = start + pageSize < rows.length;
4607
4643
  return new Paginator(new ArkormCollection(pageRows), pageSize, currentPage, hasMorePages, options);
4608
4644
  }
4609
- const currentPage = Math.max(1, page);
4610
4645
  const pageSize = Math.max(1, perPage);
4611
4646
  const items = await this.clone().skip((currentPage - 1) * pageSize).take(pageSize + 1).get();
4612
4647
  const hasMorePages = items.all().length > pageSize;
@@ -4885,11 +4920,15 @@ var Model = class Model {
4885
4920
  this.fill(attributes);
4886
4921
  return new Proxy(this, {
4887
4922
  get: (target, key, receiver) => {
4888
- if (typeof key !== "string" || key in target) return Reflect.get(target, key, receiver);
4923
+ if (typeof key !== "string") return Reflect.get(target, key, receiver);
4924
+ const attributeMutator = target.resolveAttributeMutator(key);
4925
+ if (key in target && !attributeMutator) return Reflect.get(target, key, receiver);
4889
4926
  return target.getAttribute(key);
4890
4927
  },
4891
4928
  set: (target, key, value, receiver) => {
4892
- if (typeof key !== "string" || key in target) return Reflect.set(target, key, value, receiver);
4929
+ if (typeof key !== "string") return Reflect.set(target, key, value, receiver);
4930
+ const attributeMutator = target.resolveAttributeMutator(key);
4931
+ if (key in target && !attributeMutator) return Reflect.set(target, key, value, receiver);
4893
4932
  target.setAttribute(key, value);
4894
4933
  return true;
4895
4934
  }
@@ -5078,18 +5117,22 @@ var Model = class Model {
5078
5117
  return this;
5079
5118
  }
5080
5119
  getAttribute(key) {
5120
+ const attributeMutator = this.resolveAttributeMutator(key);
5081
5121
  const mutator = this.resolveGetMutator(key);
5082
5122
  const cast = this.casts[key];
5083
5123
  let value = this.attributes[key];
5084
5124
  if (cast) value = resolveCast(cast).get(value);
5125
+ if (attributeMutator?.get) return attributeMutator.get.call(this, value);
5085
5126
  if (mutator) return mutator.call(this, value);
5086
5127
  return value;
5087
5128
  }
5088
5129
  setAttribute(key, value) {
5130
+ const attributeMutator = this.resolveAttributeMutator(key);
5089
5131
  const mutator = this.resolveSetMutator(key);
5090
5132
  const cast = this.casts[key];
5091
5133
  let resolved = value;
5092
- if (mutator) resolved = mutator.call(this, resolved);
5134
+ if (attributeMutator?.set) resolved = attributeMutator.set.call(this, resolved);
5135
+ else if (mutator) resolved = mutator.call(this, resolved);
5093
5136
  if (cast) resolved = resolveCast(cast).set(resolved);
5094
5137
  this.attributes[key] = resolved;
5095
5138
  return this;
@@ -5357,6 +5400,24 @@ var Model = class Model {
5357
5400
  return typeof method === "function" ? method : null;
5358
5401
  }
5359
5402
  /**
5403
+ * Resolve an Attribute object mutator method for a given key, if it exists.
5404
+ *
5405
+ * @param key
5406
+ * @returns
5407
+ */
5408
+ resolveAttributeMutator(key) {
5409
+ if (key === "constructor") return null;
5410
+ const methodName = `${str(key).camel()}`;
5411
+ const prototype = Object.getPrototypeOf(this);
5412
+ if (!prototype) return null;
5413
+ const method = prototype[methodName];
5414
+ if (typeof method !== "function") return null;
5415
+ if (method === Model.prototype[methodName]) return null;
5416
+ const resolved = method.call(this);
5417
+ if (Attribute.isAttribute(resolved)) return resolved;
5418
+ return null;
5419
+ }
5420
+ /**
5360
5421
  * Resolve a set mutator method for a given attribute key, if it exists.
5361
5422
  *
5362
5423
  * @param key
@@ -5408,4 +5469,4 @@ var Model = class Model {
5408
5469
  };
5409
5470
 
5410
5471
  //#endregion
5411
- export { ArkormCollection, ArkormException, CliApp, ForeignKeyBuilder, InitCommand, InlineFactory, LengthAwarePaginator, MIGRATION_BRAND, MakeFactoryCommand, MakeMigrationCommand, MakeModelCommand, MakeSeederCommand, MigrateCommand, MigrateRollbackCommand, Migration, MigrationHistoryCommand, Model, ModelFactory, ModelNotFoundException, ModelsSyncCommand, PRISMA_MODEL_REGEX, Paginator, QueryBuilder, SEEDER_BRAND, SchemaBuilder, SeedCommand, Seeder, TableBuilder, URLDriver, applyAlterTableOperation, applyCreateTableOperation, applyDropTableOperation, applyMigrationRollbackToPrismaSchema, applyMigrationToPrismaSchema, applyOperationsToPrismaSchema, buildFieldLine, buildIndexLine, buildInverseRelationLine, buildMigrationIdentity, buildMigrationRunId, buildMigrationSource, buildModelBlock, buildRelationLine, computeMigrationChecksum, configureArkormRuntime, createMigrationTimestamp, createPrismaAdapter, createPrismaDelegateMap, defineConfig, defineFactory, deriveCollectionFieldName, deriveInverseRelationAlias, deriveRelationFieldName, ensureArkormConfigLoading, escapeRegex, findAppliedMigration, findModelBlock, formatDefaultValue, formatRelationAction, generateMigrationFile, getDefaultStubsPath, getLastMigrationRun, getLatestAppliedMigrations, getMigrationPlan, getRuntimePaginationURLDriverFactory, getRuntimePrismaClient, getUserConfig, inferDelegateName, isDelegateLike, isMigrationApplied, loadArkormConfig, markMigrationApplied, markMigrationRun, pad, readAppliedMigrationsState, removeAppliedMigration, resetArkormRuntimeForTests, resolveCast, resolveMigrationClassName, resolveMigrationStateFilePath, resolvePrismaType, runMigrationWithPrisma, runPrismaCommand, toMigrationFileSlug, toModelName, writeAppliedMigrationsState };
5472
+ export { ArkormCollection, ArkormException, Attribute, CliApp, ForeignKeyBuilder, InitCommand, InlineFactory, LengthAwarePaginator, MIGRATION_BRAND, MakeFactoryCommand, MakeMigrationCommand, MakeModelCommand, MakeSeederCommand, MigrateCommand, MigrateRollbackCommand, Migration, MigrationHistoryCommand, Model, ModelFactory, ModelNotFoundException, ModelsSyncCommand, PRISMA_MODEL_REGEX, Paginator, QueryBuilder, SEEDER_BRAND, SchemaBuilder, SeedCommand, Seeder, TableBuilder, URLDriver, applyAlterTableOperation, applyCreateTableOperation, applyDropTableOperation, applyMigrationRollbackToPrismaSchema, applyMigrationToPrismaSchema, applyOperationsToPrismaSchema, buildFieldLine, buildIndexLine, buildInverseRelationLine, buildMigrationIdentity, buildMigrationRunId, buildMigrationSource, buildModelBlock, buildRelationLine, computeMigrationChecksum, configureArkormRuntime, createMigrationTimestamp, createPrismaAdapter, createPrismaDelegateMap, defineConfig, defineFactory, deriveCollectionFieldName, deriveInverseRelationAlias, deriveRelationFieldName, ensureArkormConfigLoading, escapeRegex, findAppliedMigration, findModelBlock, formatDefaultValue, formatRelationAction, generateMigrationFile, getDefaultStubsPath, getLastMigrationRun, getLatestAppliedMigrations, getMigrationPlan, getRuntimePaginationCurrentPageResolver, getRuntimePaginationURLDriverFactory, getRuntimePrismaClient, getUserConfig, inferDelegateName, isDelegateLike, isMigrationApplied, loadArkormConfig, markMigrationApplied, markMigrationRun, pad, readAppliedMigrationsState, removeAppliedMigration, resetArkormRuntimeForTests, resolveCast, resolveMigrationClassName, resolveMigrationStateFilePath, resolvePrismaType, runMigrationWithPrisma, runPrismaCommand, toMigrationFileSlug, toModelName, writeAppliedMigrationsState };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkormx",
3
- "version": "0.2.9",
3
+ "version": "0.2.11",
4
4
  "description": "Modern TypeScript-first ORM for Node.js.",
5
5
  "keywords": [
6
6
  "orm",