arkormx 2.0.0-next.21 → 2.0.0-next.23

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.cjs CHANGED
@@ -2384,7 +2384,7 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
2384
2384
  relationLoads: false,
2385
2385
  relationAggregates: true,
2386
2386
  relationFilters: true,
2387
- rawWhere: false
2387
+ rawWhere: true
2388
2388
  };
2389
2389
  constructor(db, mapping = {}) {
2390
2390
  this.db = db;
@@ -2669,6 +2669,18 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
2669
2669
  if (condition.operator === "ends-with") return kysely.sql`${column} like ${`%${String(condition.value ?? "")}`}`;
2670
2670
  return kysely.sql`${column} ${condition.operator === "!=" ? kysely.sql.raw("!=") : kysely.sql.raw(condition.operator)} ${condition.value}`;
2671
2671
  }
2672
+ buildRawWhereCondition(condition) {
2673
+ const segments = condition.sql.split("?");
2674
+ const bindings = condition.bindings ?? [];
2675
+ if (segments.length !== bindings.length + 1) throw new ArkormException("Raw where bindings do not match the number of placeholders.");
2676
+ const parts = [];
2677
+ segments.forEach((segment, index) => {
2678
+ if (segment.length > 0) parts.push(kysely.sql.raw(segment));
2679
+ if (index < bindings.length) parts.push(kysely.sql`${bindings[index]}`);
2680
+ });
2681
+ if (parts.length === 0) return kysely.sql`1 = 1`;
2682
+ return kysely.sql`${kysely.sql.join(parts, kysely.sql``)}`;
2683
+ }
2672
2684
  buildWhereCondition(target, condition) {
2673
2685
  if (!condition) return kysely.sql`1 = 1`;
2674
2686
  if (condition.type === "comparison") return this.buildComparisonCondition(target, condition);
@@ -2685,13 +2697,7 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
2685
2697
  const notCondition = condition;
2686
2698
  return kysely.sql`not (${this.buildWhereCondition(target, notCondition.condition)})`;
2687
2699
  }
2688
- throw new UnsupportedAdapterFeatureException("Raw where clauses are not supported by the Kysely adapter.", {
2689
- operation: "adapter.where",
2690
- meta: {
2691
- feature: "rawWhere",
2692
- sql: condition.sql
2693
- }
2694
- });
2700
+ return this.buildRawWhereCondition(condition);
2695
2701
  }
2696
2702
  buildWhereClause(target, condition) {
2697
2703
  if (!condition) return kysely.sql``;
@@ -6004,7 +6010,7 @@ var RelationTableLoader = class {
6004
6010
  * @author Legacy (3m1n3nc3)
6005
6011
  * @since 2.0.0-next.2
6006
6012
  */
6007
- var SetBasedEagerLoader = class {
6013
+ var SetBasedEagerLoader = class SetBasedEagerLoader {
6008
6014
  constructor(models, relations) {
6009
6015
  this.models = models;
6010
6016
  this.relations = relations;
@@ -6016,10 +6022,18 @@ var SetBasedEagerLoader = class {
6016
6022
  */
6017
6023
  async load() {
6018
6024
  if (this.models.length === 0) return;
6019
- await Promise.all(Object.entries(this.relations).map(async ([name, constraint]) => {
6020
- await this.loadRelation(name, constraint);
6025
+ const relationTree = this.buildRelationTree(this.relations);
6026
+ await Promise.all(Array.from(relationTree.entries()).map(async ([name, node]) => {
6027
+ await this.loadRelationNode(name, node);
6021
6028
  }));
6022
6029
  }
6030
+ async loadRelationNode(name, node) {
6031
+ await this.loadRelation(name, node.constraint);
6032
+ if (node.children.size === 0) return;
6033
+ const relatedModels = this.collectLoadedRelationModels(name);
6034
+ if (relatedModels.length === 0) return;
6035
+ await new SetBasedEagerLoader(relatedModels, this.relationTreeToMap(node.children)).load();
6036
+ }
6023
6037
  /**
6024
6038
  * Loads a specific relationship for the set of models based on the relationship name
6025
6039
  * and an optional constraint.
@@ -6063,9 +6077,58 @@ var SetBasedEagerLoader = class {
6063
6077
  */
6064
6078
  resolveRelationResolver(name) {
6065
6079
  const resolver = this.models[0][name];
6066
- if (typeof resolver !== "function") return null;
6080
+ if (typeof resolver !== "function") {
6081
+ const modelName = this.models[0].constructor?.name ?? "Model";
6082
+ throw new RelationResolutionException(`Relation [${name}] is not defined on the model.`, {
6083
+ operation: "eagerLoad",
6084
+ model: modelName,
6085
+ relation: name
6086
+ });
6087
+ }
6067
6088
  return resolver;
6068
6089
  }
6090
+ buildRelationTree(relations) {
6091
+ const tree = /* @__PURE__ */ new Map();
6092
+ Object.entries(relations).forEach(([path, constraint]) => {
6093
+ const segments = path.split(".").map((segment) => segment.trim()).filter((segment) => segment.length > 0);
6094
+ if (segments.length === 0) return;
6095
+ let current = tree;
6096
+ segments.forEach((segment, index) => {
6097
+ const existing = current.get(segment) ?? {
6098
+ constraint: void 0,
6099
+ children: /* @__PURE__ */ new Map()
6100
+ };
6101
+ if (index === segments.length - 1 && constraint) existing.constraint = constraint;
6102
+ current.set(segment, existing);
6103
+ current = existing.children;
6104
+ });
6105
+ });
6106
+ return tree;
6107
+ }
6108
+ relationTreeToMap(tree, prefix = "") {
6109
+ return Array.from(tree.entries()).reduce((all, [name, node]) => {
6110
+ const path = prefix ? `${prefix}.${name}` : name;
6111
+ all[path] = node.constraint;
6112
+ Object.assign(all, this.relationTreeToMap(node.children, path));
6113
+ return all;
6114
+ }, {});
6115
+ }
6116
+ collectLoadedRelationModels(name) {
6117
+ return this.models.reduce((all, model) => {
6118
+ const loaded = model.getAttribute(name);
6119
+ if (loaded instanceof ArkormCollection) {
6120
+ loaded.all().forEach((item) => {
6121
+ if (this.isEagerLoadableModel(item)) all.push(item);
6122
+ });
6123
+ return all;
6124
+ }
6125
+ if (this.isEagerLoadableModel(loaded)) all.push(loaded);
6126
+ return all;
6127
+ }, []);
6128
+ }
6129
+ isEagerLoadableModel(value) {
6130
+ return typeof value === "object" && value !== null && typeof value.getAttribute === "function" && typeof value.setLoadedRelation === "function";
6131
+ }
6069
6132
  /**
6070
6133
  * Loads a "belongs to" relationship for the set of models.
6071
6134
  *
@@ -6701,6 +6764,36 @@ var QueryBuilder = class QueryBuilder {
6701
6764
  return this.where({ [key]: { notIn: values } });
6702
6765
  }
6703
6766
  /**
6767
+ * Adds a string contains clause for a single attribute key.
6768
+ *
6769
+ * @param key
6770
+ * @param value
6771
+ * @returns
6772
+ */
6773
+ whereLike(key, value) {
6774
+ return this.where({ [key]: { contains: value } });
6775
+ }
6776
+ /**
6777
+ * Adds a string starts-with clause for a single attribute key.
6778
+ *
6779
+ * @param key
6780
+ * @param value
6781
+ * @returns
6782
+ */
6783
+ whereStartsWith(key, value) {
6784
+ return this.where({ [key]: { startsWith: value } });
6785
+ }
6786
+ /**
6787
+ * Adds a string ends-with clause for a single attribute key.
6788
+ *
6789
+ * @param key
6790
+ * @param value
6791
+ * @returns
6792
+ */
6793
+ whereEndsWith(key, value) {
6794
+ return this.where({ [key]: { endsWith: value } });
6795
+ }
6796
+ /**
6704
6797
  * Adds a strongly-typed OR NOT IN where clause for a single attribute key.
6705
6798
  *
6706
6799
  * @param key
@@ -8825,6 +8918,36 @@ var Relation = class {
8825
8918
  return this.constrain((query) => query.whereIn(key, values));
8826
8919
  }
8827
8920
  /**
8921
+ * Add a string contains clause to the relationship query.
8922
+ *
8923
+ * @param key
8924
+ * @param value
8925
+ * @returns
8926
+ */
8927
+ whereLike(key, value) {
8928
+ return this.constrain((query) => query.whereLike(key, value));
8929
+ }
8930
+ /**
8931
+ * Add a string starts-with clause to the relationship query.
8932
+ *
8933
+ * @param key
8934
+ * @param value
8935
+ * @returns
8936
+ */
8937
+ whereStartsWith(key, value) {
8938
+ return this.constrain((query) => query.whereStartsWith(key, value));
8939
+ }
8940
+ /**
8941
+ * Add a string ends-with clause to the relationship query.
8942
+ *
8943
+ * @param key
8944
+ * @param value
8945
+ * @returns
8946
+ */
8947
+ whereEndsWith(key, value) {
8948
+ return this.constrain((query) => query.whereEndsWith(key, value));
8949
+ }
8950
+ /**
8828
8951
  * Add an order by clause to the relationship query.
8829
8952
  *
8830
8953
  * @param orderBy
package/dist/index.d.cts CHANGED
@@ -554,6 +554,30 @@ declare abstract class Relation<TModel> {
554
554
  * @returns
555
555
  */
556
556
  whereIn<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, values: ModelAttributes<TModel>[TKey][]): this;
557
+ /**
558
+ * Add a string contains clause to the relationship query.
559
+ *
560
+ * @param key
561
+ * @param value
562
+ * @returns
563
+ */
564
+ whereLike<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
565
+ /**
566
+ * Add a string starts-with clause to the relationship query.
567
+ *
568
+ * @param key
569
+ * @param value
570
+ * @returns
571
+ */
572
+ whereStartsWith<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
573
+ /**
574
+ * Add a string ends-with clause to the relationship query.
575
+ *
576
+ * @param key
577
+ * @param value
578
+ * @returns
579
+ */
580
+ whereEndsWith<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
557
581
  /**
558
582
  * Add an order by clause to the relationship query.
559
583
  *
@@ -2176,6 +2200,30 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
2176
2200
  * @returns
2177
2201
  */
2178
2202
  whereNotIn<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, values: ModelAttributes<TModel>[TKey][]): this;
2203
+ /**
2204
+ * Adds a string contains clause for a single attribute key.
2205
+ *
2206
+ * @param key
2207
+ * @param value
2208
+ * @returns
2209
+ */
2210
+ whereLike<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
2211
+ /**
2212
+ * Adds a string starts-with clause for a single attribute key.
2213
+ *
2214
+ * @param key
2215
+ * @param value
2216
+ * @returns
2217
+ */
2218
+ whereStartsWith<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
2219
+ /**
2220
+ * Adds a string ends-with clause for a single attribute key.
2221
+ *
2222
+ * @param key
2223
+ * @param value
2224
+ * @returns
2225
+ */
2226
+ whereEndsWith<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
2179
2227
  /**
2180
2228
  * Adds a strongly-typed OR NOT IN where clause for a single attribute key.
2181
2229
  *
@@ -3162,6 +3210,7 @@ declare class KyselyDatabaseAdapter implements DatabaseAdapter {
3162
3210
  private buildOrderBy;
3163
3211
  private buildConditionValueList;
3164
3212
  private buildComparisonCondition;
3213
+ private buildRawWhereCondition;
3165
3214
  private buildWhereCondition;
3166
3215
  private buildWhereClause;
3167
3216
  private buildPaginationClause;
package/dist/index.d.mts CHANGED
@@ -554,6 +554,30 @@ declare abstract class Relation<TModel> {
554
554
  * @returns
555
555
  */
556
556
  whereIn<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, values: ModelAttributes<TModel>[TKey][]): this;
557
+ /**
558
+ * Add a string contains clause to the relationship query.
559
+ *
560
+ * @param key
561
+ * @param value
562
+ * @returns
563
+ */
564
+ whereLike<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
565
+ /**
566
+ * Add a string starts-with clause to the relationship query.
567
+ *
568
+ * @param key
569
+ * @param value
570
+ * @returns
571
+ */
572
+ whereStartsWith<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
573
+ /**
574
+ * Add a string ends-with clause to the relationship query.
575
+ *
576
+ * @param key
577
+ * @param value
578
+ * @returns
579
+ */
580
+ whereEndsWith<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
557
581
  /**
558
582
  * Add an order by clause to the relationship query.
559
583
  *
@@ -2176,6 +2200,30 @@ declare class QueryBuilder<TModel, TDelegate extends PrismaDelegateLike = Prisma
2176
2200
  * @returns
2177
2201
  */
2178
2202
  whereNotIn<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, values: ModelAttributes<TModel>[TKey][]): this;
2203
+ /**
2204
+ * Adds a string contains clause for a single attribute key.
2205
+ *
2206
+ * @param key
2207
+ * @param value
2208
+ * @returns
2209
+ */
2210
+ whereLike<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
2211
+ /**
2212
+ * Adds a string starts-with clause for a single attribute key.
2213
+ *
2214
+ * @param key
2215
+ * @param value
2216
+ * @returns
2217
+ */
2218
+ whereStartsWith<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
2219
+ /**
2220
+ * Adds a string ends-with clause for a single attribute key.
2221
+ *
2222
+ * @param key
2223
+ * @param value
2224
+ * @returns
2225
+ */
2226
+ whereEndsWith<TKey extends keyof ModelAttributes<TModel> & string>(key: TKey, value: Extract<ModelAttributes<TModel>[TKey], string>): this;
2179
2227
  /**
2180
2228
  * Adds a strongly-typed OR NOT IN where clause for a single attribute key.
2181
2229
  *
@@ -3162,6 +3210,7 @@ declare class KyselyDatabaseAdapter implements DatabaseAdapter {
3162
3210
  private buildOrderBy;
3163
3211
  private buildConditionValueList;
3164
3212
  private buildComparisonCondition;
3213
+ private buildRawWhereCondition;
3165
3214
  private buildWhereCondition;
3166
3215
  private buildWhereClause;
3167
3216
  private buildPaginationClause;
package/dist/index.mjs CHANGED
@@ -2355,7 +2355,7 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
2355
2355
  relationLoads: false,
2356
2356
  relationAggregates: true,
2357
2357
  relationFilters: true,
2358
- rawWhere: false
2358
+ rawWhere: true
2359
2359
  };
2360
2360
  constructor(db, mapping = {}) {
2361
2361
  this.db = db;
@@ -2640,6 +2640,18 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
2640
2640
  if (condition.operator === "ends-with") return sql`${column} like ${`%${String(condition.value ?? "")}`}`;
2641
2641
  return sql`${column} ${condition.operator === "!=" ? sql.raw("!=") : sql.raw(condition.operator)} ${condition.value}`;
2642
2642
  }
2643
+ buildRawWhereCondition(condition) {
2644
+ const segments = condition.sql.split("?");
2645
+ const bindings = condition.bindings ?? [];
2646
+ if (segments.length !== bindings.length + 1) throw new ArkormException("Raw where bindings do not match the number of placeholders.");
2647
+ const parts = [];
2648
+ segments.forEach((segment, index) => {
2649
+ if (segment.length > 0) parts.push(sql.raw(segment));
2650
+ if (index < bindings.length) parts.push(sql`${bindings[index]}`);
2651
+ });
2652
+ if (parts.length === 0) return sql`1 = 1`;
2653
+ return sql`${sql.join(parts, sql``)}`;
2654
+ }
2643
2655
  buildWhereCondition(target, condition) {
2644
2656
  if (!condition) return sql`1 = 1`;
2645
2657
  if (condition.type === "comparison") return this.buildComparisonCondition(target, condition);
@@ -2656,13 +2668,7 @@ var KyselyDatabaseAdapter = class KyselyDatabaseAdapter {
2656
2668
  const notCondition = condition;
2657
2669
  return sql`not (${this.buildWhereCondition(target, notCondition.condition)})`;
2658
2670
  }
2659
- throw new UnsupportedAdapterFeatureException("Raw where clauses are not supported by the Kysely adapter.", {
2660
- operation: "adapter.where",
2661
- meta: {
2662
- feature: "rawWhere",
2663
- sql: condition.sql
2664
- }
2665
- });
2671
+ return this.buildRawWhereCondition(condition);
2666
2672
  }
2667
2673
  buildWhereClause(target, condition) {
2668
2674
  if (!condition) return sql``;
@@ -5975,7 +5981,7 @@ var RelationTableLoader = class {
5975
5981
  * @author Legacy (3m1n3nc3)
5976
5982
  * @since 2.0.0-next.2
5977
5983
  */
5978
- var SetBasedEagerLoader = class {
5984
+ var SetBasedEagerLoader = class SetBasedEagerLoader {
5979
5985
  constructor(models, relations) {
5980
5986
  this.models = models;
5981
5987
  this.relations = relations;
@@ -5987,10 +5993,18 @@ var SetBasedEagerLoader = class {
5987
5993
  */
5988
5994
  async load() {
5989
5995
  if (this.models.length === 0) return;
5990
- await Promise.all(Object.entries(this.relations).map(async ([name, constraint]) => {
5991
- await this.loadRelation(name, constraint);
5996
+ const relationTree = this.buildRelationTree(this.relations);
5997
+ await Promise.all(Array.from(relationTree.entries()).map(async ([name, node]) => {
5998
+ await this.loadRelationNode(name, node);
5992
5999
  }));
5993
6000
  }
6001
+ async loadRelationNode(name, node) {
6002
+ await this.loadRelation(name, node.constraint);
6003
+ if (node.children.size === 0) return;
6004
+ const relatedModels = this.collectLoadedRelationModels(name);
6005
+ if (relatedModels.length === 0) return;
6006
+ await new SetBasedEagerLoader(relatedModels, this.relationTreeToMap(node.children)).load();
6007
+ }
5994
6008
  /**
5995
6009
  * Loads a specific relationship for the set of models based on the relationship name
5996
6010
  * and an optional constraint.
@@ -6034,9 +6048,58 @@ var SetBasedEagerLoader = class {
6034
6048
  */
6035
6049
  resolveRelationResolver(name) {
6036
6050
  const resolver = this.models[0][name];
6037
- if (typeof resolver !== "function") return null;
6051
+ if (typeof resolver !== "function") {
6052
+ const modelName = this.models[0].constructor?.name ?? "Model";
6053
+ throw new RelationResolutionException(`Relation [${name}] is not defined on the model.`, {
6054
+ operation: "eagerLoad",
6055
+ model: modelName,
6056
+ relation: name
6057
+ });
6058
+ }
6038
6059
  return resolver;
6039
6060
  }
6061
+ buildRelationTree(relations) {
6062
+ const tree = /* @__PURE__ */ new Map();
6063
+ Object.entries(relations).forEach(([path, constraint]) => {
6064
+ const segments = path.split(".").map((segment) => segment.trim()).filter((segment) => segment.length > 0);
6065
+ if (segments.length === 0) return;
6066
+ let current = tree;
6067
+ segments.forEach((segment, index) => {
6068
+ const existing = current.get(segment) ?? {
6069
+ constraint: void 0,
6070
+ children: /* @__PURE__ */ new Map()
6071
+ };
6072
+ if (index === segments.length - 1 && constraint) existing.constraint = constraint;
6073
+ current.set(segment, existing);
6074
+ current = existing.children;
6075
+ });
6076
+ });
6077
+ return tree;
6078
+ }
6079
+ relationTreeToMap(tree, prefix = "") {
6080
+ return Array.from(tree.entries()).reduce((all, [name, node]) => {
6081
+ const path = prefix ? `${prefix}.${name}` : name;
6082
+ all[path] = node.constraint;
6083
+ Object.assign(all, this.relationTreeToMap(node.children, path));
6084
+ return all;
6085
+ }, {});
6086
+ }
6087
+ collectLoadedRelationModels(name) {
6088
+ return this.models.reduce((all, model) => {
6089
+ const loaded = model.getAttribute(name);
6090
+ if (loaded instanceof ArkormCollection) {
6091
+ loaded.all().forEach((item) => {
6092
+ if (this.isEagerLoadableModel(item)) all.push(item);
6093
+ });
6094
+ return all;
6095
+ }
6096
+ if (this.isEagerLoadableModel(loaded)) all.push(loaded);
6097
+ return all;
6098
+ }, []);
6099
+ }
6100
+ isEagerLoadableModel(value) {
6101
+ return typeof value === "object" && value !== null && typeof value.getAttribute === "function" && typeof value.setLoadedRelation === "function";
6102
+ }
6040
6103
  /**
6041
6104
  * Loads a "belongs to" relationship for the set of models.
6042
6105
  *
@@ -6672,6 +6735,36 @@ var QueryBuilder = class QueryBuilder {
6672
6735
  return this.where({ [key]: { notIn: values } });
6673
6736
  }
6674
6737
  /**
6738
+ * Adds a string contains clause for a single attribute key.
6739
+ *
6740
+ * @param key
6741
+ * @param value
6742
+ * @returns
6743
+ */
6744
+ whereLike(key, value) {
6745
+ return this.where({ [key]: { contains: value } });
6746
+ }
6747
+ /**
6748
+ * Adds a string starts-with clause for a single attribute key.
6749
+ *
6750
+ * @param key
6751
+ * @param value
6752
+ * @returns
6753
+ */
6754
+ whereStartsWith(key, value) {
6755
+ return this.where({ [key]: { startsWith: value } });
6756
+ }
6757
+ /**
6758
+ * Adds a string ends-with clause for a single attribute key.
6759
+ *
6760
+ * @param key
6761
+ * @param value
6762
+ * @returns
6763
+ */
6764
+ whereEndsWith(key, value) {
6765
+ return this.where({ [key]: { endsWith: value } });
6766
+ }
6767
+ /**
6675
6768
  * Adds a strongly-typed OR NOT IN where clause for a single attribute key.
6676
6769
  *
6677
6770
  * @param key
@@ -8796,6 +8889,36 @@ var Relation = class {
8796
8889
  return this.constrain((query) => query.whereIn(key, values));
8797
8890
  }
8798
8891
  /**
8892
+ * Add a string contains clause to the relationship query.
8893
+ *
8894
+ * @param key
8895
+ * @param value
8896
+ * @returns
8897
+ */
8898
+ whereLike(key, value) {
8899
+ return this.constrain((query) => query.whereLike(key, value));
8900
+ }
8901
+ /**
8902
+ * Add a string starts-with clause to the relationship query.
8903
+ *
8904
+ * @param key
8905
+ * @param value
8906
+ * @returns
8907
+ */
8908
+ whereStartsWith(key, value) {
8909
+ return this.constrain((query) => query.whereStartsWith(key, value));
8910
+ }
8911
+ /**
8912
+ * Add a string ends-with clause to the relationship query.
8913
+ *
8914
+ * @param key
8915
+ * @param value
8916
+ * @returns
8917
+ */
8918
+ whereEndsWith(key, value) {
8919
+ return this.constrain((query) => query.whereEndsWith(key, value));
8920
+ }
8921
+ /**
8799
8922
  * Add an order by clause to the relationship query.
8800
8923
  *
8801
8924
  * @param orderBy
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arkormx",
3
- "version": "2.0.0-next.21",
3
+ "version": "2.0.0-next.23",
4
4
  "description": "Modern TypeScript-first ORM for Node.js.",
5
5
  "keywords": [
6
6
  "orm",