bigal 15.0.0 → 15.1.0

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/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # [15.1.0](https://github.com/bigalorm/bigal/compare/v15.0.1...v15.1.0) (2026-01-07)
2
+
3
+ ### Features
4
+
5
+ - Add `and` property to WhereQuery for combining OR groups ([#262](https://github.com/bigalorm/bigal/issues/262)) ([903eeb8](https://github.com/bigalorm/bigal/commit/903eeb826e3dedd7574aa940527ca07b264a40b2))
6
+
7
+ ## [15.0.1](https://github.com/bigalorm/bigal/compare/v15.0.0...v15.0.1) (2026-01-07)
8
+
1
9
  # [15.0.0](https://github.com/bigalorm/bigal/compare/v14.1.26...v15.0.0) (2025-12-28)
2
10
 
3
11
  - feat!: support pluggable PostgreSQL drivers ([7638343](https://github.com/bigalorm/bigal/commit/76383432acc8ee1bdf48a8c60a8e5fa10176bd69))
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  [![node version](https://img.shields.io/node/v/bigal.svg?style=flat)](https://nodejs.org)
5
5
  [![Known Vulnerabilities](https://snyk.io/test/npm/bigal/badge.svg)](https://snyk.io/test/npm/bigal)
6
6
 
7
- A fast, lightweight ORM for PostgreSQL and node.js, written in Typescript.
7
+ A fast, lightweight ORM for PostgreSQL and Node.js, written in TypeScript.
8
8
 
9
9
  This ORM does not:
10
10
 
@@ -365,6 +365,34 @@ Equivalent to:
365
365
  select id,first_name as firstName,last_name as lastName,created_at as createdAt from person where created_at >= $1 AND created_at < $2
366
366
  ```
367
367
 
368
+ #### Using `or` for OR conditions across different columns
369
+
370
+ ```ts
371
+ const items = await PersonRepository.find().where({
372
+ or: [{ firstName: 'Walter' }, { lastName: 'White' }],
373
+ });
374
+ ```
375
+
376
+ Equivalent to:
377
+
378
+ ```postgresql
379
+ select * from person where (first_name = $1) OR (last_name = $2)
380
+ ```
381
+
382
+ #### Using `and` to combine multiple OR groups
383
+
384
+ ```ts
385
+ const items = await PersonRepository.find().where({
386
+ and: [{ or: [{ firstName: 'Walter' }, { lastName: 'White' }] }, { or: [{ firstName: 'Jesse' }, { lastName: 'Pinkman' }] }],
387
+ });
388
+ ```
389
+
390
+ Equivalent to:
391
+
392
+ ```postgresql
393
+ select * from person where ((first_name = $1) OR (last_name = $2)) AND ((first_name = $3) OR (last_name = $4))
394
+ ```
395
+
368
396
  #### Fetch multiple objects and perform a db sort before returning result
369
397
 
370
398
  ```ts
@@ -721,7 +749,7 @@ export class Store extends Entity {
721
749
 
722
750
  #### Non-entity object arrays
723
751
 
724
- If you have a json property, with an `id` field, on an entity model, TypeScript will probably think it is a BigAl
752
+ If you have a JSON property, with an `id` field, on an entity model, TypeScript will probably think it is a BigAl
725
753
  entity due to how the type system works. In that case, you'll want to wrap the type with `NotEntity<>`. For example:
726
754
 
727
755
  ```ts
package/dist/index.cjs CHANGED
@@ -964,6 +964,15 @@ function buildWhere({
964
964
  params
965
965
  });
966
966
  default: {
967
+ if (comparer === "and" && Array.isArray(value)) {
968
+ return buildAndOperatorStatement({
969
+ repositoriesByModelNameLowered,
970
+ model,
971
+ isNegated,
972
+ value,
973
+ params
974
+ });
975
+ }
967
976
  if (value === void 0) {
968
977
  throw new QueryError(`Attempting to query with an undefined value. ${propertyName ?? ""} on ${model.name}`, model);
969
978
  }
@@ -1202,6 +1211,37 @@ function buildOrOperatorStatement({
1202
1211
  }
1203
1212
  return "";
1204
1213
  }
1214
+ function buildAndOperatorStatement({
1215
+ repositoriesByModelNameLowered,
1216
+ model,
1217
+ isNegated,
1218
+ value,
1219
+ params
1220
+ }) {
1221
+ const andClauses = [];
1222
+ for (const constraint of value) {
1223
+ const andClause = buildWhere({
1224
+ repositoriesByModelNameLowered,
1225
+ model,
1226
+ isNegated,
1227
+ value: constraint,
1228
+ params
1229
+ });
1230
+ if (andClause) {
1231
+ andClauses.push(`(${andClause})`);
1232
+ }
1233
+ }
1234
+ if (andClauses.length === 1) {
1235
+ return andClauses[0] ?? "";
1236
+ }
1237
+ if (isNegated) {
1238
+ return andClauses.join(" OR ");
1239
+ }
1240
+ if (andClauses.length) {
1241
+ return `(${andClauses.join(" AND ")})`;
1242
+ }
1243
+ return "";
1244
+ }
1205
1245
  function buildLikeOperatorStatement({ model, propertyName, isNegated, value, params }) {
1206
1246
  if (Array.isArray(value)) {
1207
1247
  if (!value.length) {
@@ -1959,7 +1999,7 @@ ${stack ?? ""}`;
1959
1999
  let relatedModelColumn;
1960
2000
  for (const populateModelColumn of populateRepository.model.columns) {
1961
2001
  const { through } = populateModelColumn;
1962
- if (through && through.toLowerCase() === column.through.toLowerCase()) {
2002
+ if (through?.toLowerCase() === column.through.toLowerCase()) {
1963
2003
  relatedModelColumn = populateModelColumn;
1964
2004
  break;
1965
2005
  }
package/dist/index.d.cts CHANGED
@@ -425,6 +425,7 @@ type WhereQueryStatement<TValue> = [TValue] extends [string] ? NegatableConstrai
425
425
  type WhereQuery<T extends Entity> = {
426
426
  [K in keyof T as ExcludeEntityCollections<T[K], ExcludeFunctions<T[K], K>>]?: K extends 'id' ? WhereQueryStatement<T | T[K]> : T[K] extends (infer U)[] | undefined ? WhereQueryStatement<ExcludeUndefined<U>> : NegatableConstraint<LiteralValues<ExcludeUndefined<T[K]>>> | WhereQueryStatement<ExcludeUndefined<T[K]>>;
427
427
  } & {
428
+ and?: WhereQuery<T>[];
428
429
  or?: WhereQuery<T>[];
429
430
  };
430
431
 
@@ -433,7 +434,7 @@ interface CountArgs<T extends Entity> {
433
434
  pool?: PoolLike;
434
435
  }
435
436
 
436
- type Comparer = '!' | '<' | '<=' | '>' | '>=' | 'contains' | 'endsWith' | 'like' | 'or' | 'startsWith';
437
+ type Comparer = '!' | '<' | '<=' | '>' | '>=' | 'and' | 'contains' | 'endsWith' | 'like' | 'or' | 'startsWith';
437
438
 
438
439
  interface CountResult<TEntity extends Entity> extends PromiseLike<number> {
439
440
  where(args: WhereQuery<TEntity>): CountResult<TEntity> | number;
package/dist/index.d.mts CHANGED
@@ -425,6 +425,7 @@ type WhereQueryStatement<TValue> = [TValue] extends [string] ? NegatableConstrai
425
425
  type WhereQuery<T extends Entity> = {
426
426
  [K in keyof T as ExcludeEntityCollections<T[K], ExcludeFunctions<T[K], K>>]?: K extends 'id' ? WhereQueryStatement<T | T[K]> : T[K] extends (infer U)[] | undefined ? WhereQueryStatement<ExcludeUndefined<U>> : NegatableConstraint<LiteralValues<ExcludeUndefined<T[K]>>> | WhereQueryStatement<ExcludeUndefined<T[K]>>;
427
427
  } & {
428
+ and?: WhereQuery<T>[];
428
429
  or?: WhereQuery<T>[];
429
430
  };
430
431
 
@@ -433,7 +434,7 @@ interface CountArgs<T extends Entity> {
433
434
  pool?: PoolLike;
434
435
  }
435
436
 
436
- type Comparer = '!' | '<' | '<=' | '>' | '>=' | 'contains' | 'endsWith' | 'like' | 'or' | 'startsWith';
437
+ type Comparer = '!' | '<' | '<=' | '>' | '>=' | 'and' | 'contains' | 'endsWith' | 'like' | 'or' | 'startsWith';
437
438
 
438
439
  interface CountResult<TEntity extends Entity> extends PromiseLike<number> {
439
440
  where(args: WhereQuery<TEntity>): CountResult<TEntity> | number;
package/dist/index.d.ts CHANGED
@@ -425,6 +425,7 @@ type WhereQueryStatement<TValue> = [TValue] extends [string] ? NegatableConstrai
425
425
  type WhereQuery<T extends Entity> = {
426
426
  [K in keyof T as ExcludeEntityCollections<T[K], ExcludeFunctions<T[K], K>>]?: K extends 'id' ? WhereQueryStatement<T | T[K]> : T[K] extends (infer U)[] | undefined ? WhereQueryStatement<ExcludeUndefined<U>> : NegatableConstraint<LiteralValues<ExcludeUndefined<T[K]>>> | WhereQueryStatement<ExcludeUndefined<T[K]>>;
427
427
  } & {
428
+ and?: WhereQuery<T>[];
428
429
  or?: WhereQuery<T>[];
429
430
  };
430
431
 
@@ -433,7 +434,7 @@ interface CountArgs<T extends Entity> {
433
434
  pool?: PoolLike;
434
435
  }
435
436
 
436
- type Comparer = '!' | '<' | '<=' | '>' | '>=' | 'contains' | 'endsWith' | 'like' | 'or' | 'startsWith';
437
+ type Comparer = '!' | '<' | '<=' | '>' | '>=' | 'and' | 'contains' | 'endsWith' | 'like' | 'or' | 'startsWith';
437
438
 
438
439
  interface CountResult<TEntity extends Entity> extends PromiseLike<number> {
439
440
  where(args: WhereQuery<TEntity>): CountResult<TEntity> | number;
package/dist/index.mjs CHANGED
@@ -962,6 +962,15 @@ function buildWhere({
962
962
  params
963
963
  });
964
964
  default: {
965
+ if (comparer === "and" && Array.isArray(value)) {
966
+ return buildAndOperatorStatement({
967
+ repositoriesByModelNameLowered,
968
+ model,
969
+ isNegated,
970
+ value,
971
+ params
972
+ });
973
+ }
965
974
  if (value === void 0) {
966
975
  throw new QueryError(`Attempting to query with an undefined value. ${propertyName ?? ""} on ${model.name}`, model);
967
976
  }
@@ -1200,6 +1209,37 @@ function buildOrOperatorStatement({
1200
1209
  }
1201
1210
  return "";
1202
1211
  }
1212
+ function buildAndOperatorStatement({
1213
+ repositoriesByModelNameLowered,
1214
+ model,
1215
+ isNegated,
1216
+ value,
1217
+ params
1218
+ }) {
1219
+ const andClauses = [];
1220
+ for (const constraint of value) {
1221
+ const andClause = buildWhere({
1222
+ repositoriesByModelNameLowered,
1223
+ model,
1224
+ isNegated,
1225
+ value: constraint,
1226
+ params
1227
+ });
1228
+ if (andClause) {
1229
+ andClauses.push(`(${andClause})`);
1230
+ }
1231
+ }
1232
+ if (andClauses.length === 1) {
1233
+ return andClauses[0] ?? "";
1234
+ }
1235
+ if (isNegated) {
1236
+ return andClauses.join(" OR ");
1237
+ }
1238
+ if (andClauses.length) {
1239
+ return `(${andClauses.join(" AND ")})`;
1240
+ }
1241
+ return "";
1242
+ }
1203
1243
  function buildLikeOperatorStatement({ model, propertyName, isNegated, value, params }) {
1204
1244
  if (Array.isArray(value)) {
1205
1245
  if (!value.length) {
@@ -1957,7 +1997,7 @@ ${stack ?? ""}`;
1957
1997
  let relatedModelColumn;
1958
1998
  for (const populateModelColumn of populateRepository.model.columns) {
1959
1999
  const { through } = populateModelColumn;
1960
- if (through && through.toLowerCase() === column.through.toLowerCase()) {
2000
+ if (through?.toLowerCase() === column.through.toLowerCase()) {
1961
2001
  relatedModelColumn = populateModelColumn;
1962
2002
  break;
1963
2003
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigal",
3
- "version": "15.0.0",
3
+ "version": "15.1.0",
4
4
  "description": "A fast and lightweight orm for postgres and node.js, written in typescript.",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.mjs",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "dependencies": {},
36
36
  "devDependencies": {
37
- "@faker-js/faker": "10.1.0",
37
+ "@faker-js/faker": "10.2.0",
38
38
  "@semantic-release/changelog": "6.0.3",
39
39
  "@semantic-release/commit-analyzer": "13.0.1",
40
40
  "@semantic-release/git": "10.0.1",
@@ -46,7 +46,7 @@
46
46
  "@types/node": ">=20",
47
47
  "chai": "6.2.2",
48
48
  "eslint": "9.39.2",
49
- "eslint-config-decent": "3.1.79",
49
+ "eslint-config-decent": "3.1.89",
50
50
  "husky": "9.1.7",
51
51
  "lint-staged": "16.2.7",
52
52
  "markdownlint-cli": "0.47.0",
@@ -56,7 +56,7 @@
56
56
  "prettier": "3.7.4",
57
57
  "semantic-release": "25.0.2",
58
58
  "strict-event-emitter-types": "2.0.0",
59
- "postgres-pool": "10.1.33",
59
+ "postgres-pool": "11.0.1",
60
60
  "ts-mockito": "2.6.1",
61
61
  "ts-node": "10.9.2",
62
62
  "typescript": "5.9.3",