bigal 15.10.2 → 15.11.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.
@@ -7,9 +7,7 @@
7
7
  },
8
8
  "customizations": {
9
9
  "vscode": {
10
- "extensions": [
11
- "EditorConfig.EditorConfig"
12
- ]
10
+ "extensions": ["EditorConfig.EditorConfig"]
13
11
  }
14
12
  },
15
13
  "postCreateCommand": "npm install"
package/.oxfmtrc.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc/oxfmt-config-schema/npm/oxfmt/configuration_schema.json",
3
+ "printWidth": 200,
4
+ "semi": true,
5
+ "singleQuote": true,
6
+ "bracketSpacing": true,
7
+ "arrowParens": "always",
8
+ "quoteProps": "as-needed",
9
+ "trailingComma": "all",
10
+ "useTabs": false,
11
+ "tabWidth": 2,
12
+ "endOfLine": "lf",
13
+ "arrayWrap": { "minElementsToWrap": 3 },
14
+ "sortImports": {
15
+ "newlinesBetween": true,
16
+ "customGroups": [
17
+ {
18
+ "groupName": "path-alias",
19
+ "elementNamePattern": ["@/**"]
20
+ }
21
+ ],
22
+ "groups": [
23
+ ["value-builtin", "type-builtin"],
24
+ { "newlinesBetween": true },
25
+ ["value-external", "type-external"],
26
+ { "newlinesBetween": true },
27
+ ["value-internal", "type-internal"],
28
+ { "newlinesBetween": true },
29
+ ["value-parent", "type-parent"],
30
+ { "newlinesBetween": true },
31
+ ["value-sibling", "type-sibling", "value-index", "type-index"],
32
+ { "newlinesBetween": true },
33
+ "path-alias"
34
+ ]
35
+ },
36
+ "sortPackageJson": false,
37
+ "ignorePatterns": ["**/node_modules/**", "**/dist/**"]
38
+ }
package/.oxlintrc.json ADDED
@@ -0,0 +1,214 @@
1
+ {
2
+ "$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/compiled-schema/oxlint.schema.json",
3
+ "options": {
4
+ "typeAware": true
5
+ },
6
+ "plugins": ["node", "jsx-a11y", "jsdoc", "vitest", "import", "promise"],
7
+ "categories": {
8
+ "correctness": "error",
9
+ "suspicious": "error",
10
+ "pedantic": "off",
11
+ "style": "off",
12
+ "restriction": "off",
13
+ "nursery": "off"
14
+ },
15
+ "rules": {
16
+ "eqeqeq": ["error", "smart"],
17
+ "no-console": "error",
18
+ "no-nested-ternary": "error",
19
+ "no-await-in-loop": "error",
20
+ "id-length": ["error", { "min": 2, "exceptions": ["e", "i", "j", "q", "x", "y", "_", "A", "D", "K", "P", "T", "U"] }],
21
+ "no-void": "off",
22
+ "no-bitwise": "off",
23
+
24
+ "curly": ["error", "all"],
25
+ "no-var": "error",
26
+ "prefer-const": ["error", { "destructuring": "any", "ignoreReadBeforeAssign": true }],
27
+ "prefer-template": "error",
28
+ "no-else-return": ["error", { "allowElseIf": false }],
29
+ "no-return-assign": ["error", "always"],
30
+ "yoda": "error",
31
+ "no-lonely-if": "error",
32
+ "no-negated-condition": "error",
33
+ "no-self-compare": "error",
34
+ "no-useless-return": "error",
35
+ "no-promise-executor-return": "error",
36
+ "no-constructor-return": "error",
37
+ "no-new-wrappers": "error",
38
+ "no-template-curly-in-string": "error",
39
+ "no-useless-computed-key": "error",
40
+ "no-sequences": "error",
41
+ "no-proto": "error",
42
+ "no-multi-assign": "error",
43
+ "no-multi-str": "error",
44
+ "no-lone-blocks": "error",
45
+ "no-labels": ["error", { "allowLoop": false, "allowSwitch": false }],
46
+ "no-label-var": "error",
47
+ "no-extra-label": "error",
48
+ "no-new-func": "error",
49
+ "no-script-url": "error",
50
+ "max-classes-per-file": ["error", 1],
51
+ "array-callback-return": ["error", { "allowImplicit": true }],
52
+ "symbol-description": "error",
53
+ "default-case": ["error", { "commentPattern": "^no default$" }],
54
+ "default-case-last": "error",
55
+ "operator-assignment": ["error", "always"],
56
+ "prefer-numeric-literals": "error",
57
+ "prefer-object-spread": "error",
58
+ "prefer-promise-reject-errors": ["error", { "allowEmptyReject": true }],
59
+ "vars-on-top": "error",
60
+ "func-names": "error",
61
+ "func-style": ["error", "declaration"],
62
+ "grouped-accessor-pairs": "error",
63
+ "guard-for-in": "error",
64
+ "sort-imports": "off",
65
+ "no-array-constructor": "error",
66
+ "no-restricted-globals": ["error", { "name": "isFinite", "message": "Use Number.isFinite instead" }, { "name": "isNaN", "message": "Use Number.isNaN instead" }],
67
+ "no-use-before-define": ["error", { "functions": false, "classes": true, "variables": true }],
68
+ "no-empty-function": ["error", { "allow": ["arrowFunctions", "functions", "methods"] }],
69
+ "no-case-declarations": "error",
70
+ "no-empty": "error",
71
+ "no-fallthrough": "error",
72
+ "no-prototype-builtins": "error",
73
+ "no-redeclare": "error",
74
+ "no-regex-spaces": "error",
75
+ "no-unreachable": "error",
76
+ "prefer-rest-params": "error",
77
+ "prefer-spread": "error",
78
+ "getter-return": ["error", { "allowImplicit": true }],
79
+ "no-undef": "off",
80
+
81
+ "no-unneeded-ternary": ["error", { "defaultAssignment": false }],
82
+
83
+ "typescript/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
84
+ "typescript/consistent-type-imports": ["error", { "prefer": "type-imports" }],
85
+ "typescript/array-type": ["error", { "default": "array" }],
86
+ "typescript/explicit-function-return-type": "off",
87
+ "typescript/prefer-nullish-coalescing": "off",
88
+ "typescript/no-unsafe-argument": "off",
89
+ "typescript/no-unsafe-assignment": "off",
90
+ "typescript/no-unsafe-call": "off",
91
+ "typescript/no-unsafe-member-access": "off",
92
+ "typescript/no-unsafe-return": "off",
93
+ "typescript/no-misused-promises": "off",
94
+ "typescript/ban-ts-comment": ["error", { "minimumDescriptionLength": 10 }],
95
+ "typescript/only-throw-error": "error",
96
+ "typescript/return-await": "error",
97
+ "typescript/no-empty-interface": "error",
98
+ "typescript/parameter-properties": ["error", { "allow": ["readonly"] }],
99
+ "typescript/no-deprecated": "off",
100
+ "typescript/no-dynamic-delete": "error",
101
+ "typescript/no-empty-object-type": "error",
102
+ "typescript/no-extraneous-class": "error",
103
+ "typescript/no-invalid-void-type": "error",
104
+ "typescript/no-mixed-enums": "error",
105
+ "typescript/no-namespace": "error",
106
+ "typescript/no-non-null-asserted-nullish-coalescing": "error",
107
+ "typescript/no-require-imports": "error",
108
+ "typescript/no-unnecessary-condition": "error",
109
+ "typescript/no-unnecessary-template-expression": "error",
110
+ "typescript/no-unnecessary-type-arguments": "error",
111
+ "typescript/no-unnecessary-type-assertion": "error",
112
+ "typescript/no-unnecessary-type-constraint": "error",
113
+ "typescript/no-unnecessary-type-parameters": "error",
114
+ "typescript/no-unsafe-enum-comparison": "error",
115
+ "typescript/no-unsafe-function-type": "error",
116
+ "typescript/no-useless-default-assignment": "error",
117
+ "typescript/prefer-literal-enum-member": "error",
118
+ "typescript/prefer-promise-reject-errors": "error",
119
+ "typescript/prefer-reduce-type-parameter": "error",
120
+ "typescript/prefer-return-this-type": "error",
121
+ "typescript/related-getter-setter-pairs": "error",
122
+ "typescript/require-await": "error",
123
+ "typescript/restrict-plus-operands": "error",
124
+ "typescript/unified-signatures": "error",
125
+ "typescript/adjacent-overload-signatures": "error",
126
+ "typescript/ban-tslint-comment": "error",
127
+ "typescript/class-literal-property-style": "error",
128
+ "typescript/consistent-generic-constructors": "error",
129
+ "typescript/consistent-indexed-object-style": "error",
130
+ "typescript/consistent-type-assertions": "error",
131
+ "typescript/consistent-type-definitions": "error",
132
+ "typescript/no-confusing-non-null-assertion": "error",
133
+ "typescript/no-inferrable-types": "error",
134
+ "typescript/non-nullable-type-assertion-style": "error",
135
+ "typescript/prefer-find": "error",
136
+ "typescript/prefer-for-of": "error",
137
+ "typescript/prefer-function-type": "error",
138
+ "typescript/prefer-includes": "error",
139
+ "typescript/prefer-optional-chain": "error",
140
+ "typescript/prefer-regexp-exec": "error",
141
+ "typescript/prefer-string-starts-ends-with": "error",
142
+ "typescript/dot-notation": "error",
143
+ "typescript/no-unnecessary-boolean-literal-compare": "error",
144
+
145
+ "react/react-in-jsx-scope": "off",
146
+ "react/exhaustive-deps": "error",
147
+ "react/rules-of-hooks": "error",
148
+ "react/display-name": ["error", { "ignoreTranspilerName": false }],
149
+ "react/jsx-no-target-blank": "error",
150
+ "react/jsx-no-useless-fragment": "error",
151
+ "react/jsx-fragments": "error",
152
+ "react/jsx-pascal-case": ["error", { "allowAllCaps": true }],
153
+ "react/no-redundant-should-component-update": "error",
154
+ "react/self-closing-comp": "error",
155
+ "react/require-render-return": "error",
156
+ "react/jsx-no-script-url": "error",
157
+ "react/no-namespace": "error",
158
+ "react/style-prop-object": "error",
159
+ "react/iframe-missing-sandbox": "error",
160
+
161
+ "import/no-named-as-default": "off",
162
+ "import/no-named-as-default-member": "off",
163
+ "import/no-unassigned-import": "off",
164
+ "import/consistent-type-specifier-style": "off",
165
+ "import/first": "error",
166
+ "import/no-duplicates": "error",
167
+
168
+ "jsx-a11y/prefer-tag-over-role": "off",
169
+ "jsx-a11y/no-static-element-interactions": "off",
170
+
171
+ "unicorn/no-array-method-this-argument": "off",
172
+ "unicorn/prefer-array-find": "error",
173
+ "unicorn/prefer-set-has": "error",
174
+ "unicorn/prefer-node-protocol": "error",
175
+ "unicorn/prefer-object-from-entries": "error",
176
+
177
+ "promise/catch-or-return": ["error", { "allowThen": true }],
178
+ "promise/param-names": "error",
179
+ "promise/always-return": "error",
180
+
181
+ "node/no-new-require": "error",
182
+ "node/no-path-concat": "error",
183
+ "node/global-require": "error",
184
+
185
+ "jsdoc/require-param": ["error", { "ignoreWhenAllParamsMissing": true }],
186
+ "jsdoc/require-param-name": "error",
187
+ "jsdoc/require-param-type": "error",
188
+
189
+ "vitest/warn-todo": "off",
190
+ "vitest/consistent-test-it": ["error", { "fn": "it" }],
191
+ "vitest/no-duplicate-hooks": "error",
192
+ "vitest/no-identical-title": "error",
193
+ "vitest/no-import-node-test": "error",
194
+ "vitest/no-test-prefixes": "error",
195
+ "vitest/prefer-comparison-matcher": "error",
196
+ "vitest/prefer-equality-matcher": "error",
197
+ "vitest/prefer-hooks-in-order": "error",
198
+ "vitest/prefer-hooks-on-top": "error",
199
+ "vitest/prefer-lowercase-title": ["error", { "ignore": ["describe"] }],
200
+ "vitest/prefer-mock-promise-shorthand": "error",
201
+ "vitest/prefer-spy-on": "error",
202
+ "vitest/prefer-strict-equal": "error",
203
+ "vitest/require-top-level-describe": "error"
204
+ },
205
+ "overrides": [
206
+ {
207
+ "files": ["**/*.test.ts", "**/*.test.tsx"],
208
+ "rules": {
209
+ "id-length": "off"
210
+ }
211
+ }
212
+ ],
213
+ "ignorePatterns": ["dist/**", "node_modules/**"]
214
+ }
package/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ # [15.11.0](https://github.com/bigalorm/bigal/compare/v15.10.2...v15.11.0) (2026-03-10)
2
+
3
+ ### Features
4
+
5
+ - Add JSONB property querying in where clauses ([#335](https://github.com/bigalorm/bigal/issues/335)) ([c03c23e](https://github.com/bigalorm/bigal/commit/c03c23ea9e676ee5bfe5edc03506f90605849c85))
6
+
1
7
  ## [15.10.2](https://github.com/bigalorm/bigal/compare/v15.10.1...v15.10.2) (2026-02-27)
2
8
 
3
9
  ## [15.10.1](https://github.com/bigalorm/bigal/compare/v15.10.0...v15.10.1) (2026-02-07)
package/README.md CHANGED
@@ -432,6 +432,117 @@ const items = await ProductRepository.find().where({
432
432
  // SQL: SELECT ... FROM product WHERE deleted_at IS NOT NULL
433
433
  ```
434
434
 
435
+ #### JSON/JSONB column queries
436
+
437
+ BigAl supports querying individual properties within JSON/JSONB columns using PostgreSQL's `->>`
438
+ (text extraction) operator. Numeric and boolean values are automatically cast using `::numeric` and
439
+ `::boolean`.
440
+
441
+ **Property equality:**
442
+
443
+ ```ts
444
+ const items = await SimpleWithJsonRepository.find().where({
445
+ bar: { theme: 'dark' },
446
+ });
447
+ // SQL: WHERE "bar"->>'theme'=$1
448
+ ```
449
+
450
+ **Comparison operators on JSON properties:**
451
+
452
+ ```ts
453
+ const items = await SimpleWithJsonRepository.find().where({
454
+ bar: { retryCount: { '>=': 3 } },
455
+ });
456
+ // SQL: WHERE ("bar"->>'retryCount')::numeric>=$1
457
+ ```
458
+
459
+ **Boolean values:**
460
+
461
+ ```ts
462
+ const items = await SimpleWithJsonRepository.find().where({
463
+ bar: { active: true },
464
+ });
465
+ // SQL: WHERE ("bar"->>'active')::boolean=$1
466
+ ```
467
+
468
+ **Null checks** — a missing JSON property returns `NULL` from `->>`, so this matches both explicit
469
+ `null` values and absent properties:
470
+
471
+ ```ts
472
+ const items = await SimpleWithJsonRepository.find().where({
473
+ bar: { deletedAt: null },
474
+ });
475
+ // SQL: WHERE "bar"->>'deletedAt' IS NULL
476
+
477
+ const items = await SimpleWithJsonRepository.find().where({
478
+ bar: { deletedAt: { '!': null } },
479
+ });
480
+ // SQL: WHERE "bar"->>'deletedAt' IS NOT NULL
481
+ ```
482
+
483
+ **Negation:**
484
+
485
+ ```ts
486
+ // Inline negation
487
+ const items = await SimpleWithJsonRepository.find().where({
488
+ bar: { status: { '!': 'archived' } },
489
+ });
490
+ // SQL: WHERE "bar"->>'status'<>$1
491
+
492
+ // Outer negation wrapping multiple properties
493
+ const items = await SimpleWithJsonRepository.find().where({
494
+ bar: { '!': { retryCount: { '>=': 5 } } },
495
+ });
496
+ // SQL: WHERE ("bar"->>'retryCount')::numeric<$1
497
+ ```
498
+
499
+ **Array values (IN):**
500
+
501
+ ```ts
502
+ const items = await SimpleWithJsonRepository.find().where({
503
+ bar: { stage: ['transcription', 'summarization'] },
504
+ });
505
+ // SQL: WHERE "bar"->>'stage'=ANY($1)
506
+ ```
507
+
508
+ **Multiple properties (AND):**
509
+
510
+ ```ts
511
+ const items = await SimpleWithJsonRepository.find().where({
512
+ bar: { retryCount: { '<': 3 }, stage: 'transcription' },
513
+ });
514
+ // SQL: WHERE ("bar"->>'retryCount')::numeric<$1 AND "bar"->>'stage'=$2
515
+ ```
516
+
517
+ **Nested objects for deep path access** — intermediate segments use `->` and the final segment uses
518
+ `->>`:
519
+
520
+ ```ts
521
+ const items = await SimpleWithJsonRepository.find().where({
522
+ bar: { failure: { stage: 'transcription' } },
523
+ });
524
+ // SQL: WHERE "bar"->'failure'->>'stage'=$1
525
+
526
+ const items = await SimpleWithJsonRepository.find().where({
527
+ bar: { a: { b: { c: 'value' } } },
528
+ });
529
+ // SQL: WHERE "bar"->'a'->'b'->>'c'=$1
530
+
531
+ const items = await SimpleWithJsonRepository.find().where({
532
+ bar: { stats: { retryCount: { '>=': 3 } } },
533
+ });
534
+ // SQL: WHERE ("bar"->'stats'->>'retryCount')::numeric>=$1
535
+ ```
536
+
537
+ **Combined `contains` and property access:**
538
+
539
+ ```ts
540
+ const items = await SimpleWithJsonRepository.find().where({
541
+ bar: { contains: { type: 'recovery' }, retryCount: { '<': 3 } },
542
+ });
543
+ // SQL: WHERE "bar"@>$1::jsonb AND ("bar"->>'retryCount')::numeric<$2
544
+ ```
545
+
435
546
  #### Example of an AND statement
436
547
 
437
548
  ```ts
package/dist/index.cjs CHANGED
@@ -459,6 +459,7 @@ class SubqueryBuilder {
459
459
  }
460
460
  /**
461
461
  * Group the subquery results by one or more columns.
462
+ * @param {(string & keyof T)[]} columns - Columns to group by
462
463
  * @returns New SubqueryBuilder with the groupBy applied
463
464
  * @example
464
465
  * subquery(ProductRepository)
@@ -472,6 +473,7 @@ class SubqueryBuilder {
472
473
  }
473
474
  /**
474
475
  * Filter groups based on aggregate values (used with groupBy).
476
+ * @param {HavingCondition} condition - Having condition to apply
475
477
  * @returns New SubqueryBuilder with the having condition applied
476
478
  * @example
477
479
  * subquery(ProductRepository)
@@ -1737,6 +1739,21 @@ function buildWhere({
1737
1739
  let subQueryComparer;
1738
1740
  if (isComparer(key)) {
1739
1741
  subQueryComparer = key;
1742
+ } else if (propertyName) {
1743
+ const parentColumn = model.columnsByPropertyName[propertyName];
1744
+ if (parentColumn?.type?.toLowerCase() === "json") {
1745
+ andValues.push(
1746
+ buildJsonPropertyClause({
1747
+ columnName: parentColumn.name,
1748
+ path: [key],
1749
+ isNegated,
1750
+ constraint: where,
1751
+ params
1752
+ })
1753
+ );
1754
+ continue;
1755
+ }
1756
+ propertyName = key;
1740
1757
  } else {
1741
1758
  propertyName = key;
1742
1759
  }
@@ -2101,6 +2118,91 @@ function buildJsonContainmentStatement({ repositoriesByModelNameLowered, model,
2101
2118
  }
2102
2119
  });
2103
2120
  }
2121
+ function getTypeCastSuffix(value) {
2122
+ if (typeof value === "number") {
2123
+ return "::numeric";
2124
+ }
2125
+ if (typeof value === "boolean") {
2126
+ return "::boolean";
2127
+ }
2128
+ return "";
2129
+ }
2130
+ function buildJsonAccessor(columnName, path) {
2131
+ let result = `"${columnName}"`;
2132
+ for (let i = 0; i < path.length; i++) {
2133
+ const arrow = i === path.length - 1 ? "->>" : "->";
2134
+ result += `${arrow}'${path[i]}'`;
2135
+ }
2136
+ return result;
2137
+ }
2138
+ function isJsonConstraintOperator(key) {
2139
+ return key === "!" || key === "<" || key === "<=" || key === ">" || key === ">=";
2140
+ }
2141
+ function buildJsonPropertyClause({
2142
+ columnName,
2143
+ path,
2144
+ isNegated,
2145
+ constraint,
2146
+ params
2147
+ }) {
2148
+ for (const segment of path) {
2149
+ assertValidSqlIdentifier(segment, `JSON property name "${segment}"`);
2150
+ }
2151
+ if (constraint === null) {
2152
+ return `${buildJsonAccessor(columnName, path)} ${isNegated ? "IS NOT" : "IS"} NULL`;
2153
+ }
2154
+ if (Array.isArray(constraint)) {
2155
+ const accessor2 = buildJsonAccessor(columnName, path);
2156
+ params.push(constraint);
2157
+ return `${accessor2}${isNegated ? "<>ALL" : "=ANY"}($${params.length})`;
2158
+ }
2159
+ if (typeof constraint === "object") {
2160
+ const entries = Object.entries(constraint);
2161
+ const firstKey = entries[0]?.[0];
2162
+ if (firstKey && isJsonConstraintOperator(firstKey)) {
2163
+ const accessor2 = buildJsonAccessor(columnName, path);
2164
+ const negatedComparisonOperators = { "<": ">=", "<=": ">", ">": "<=", ">=": "<" };
2165
+ const clauses2 = [];
2166
+ for (const [operator, operatorValue] of entries) {
2167
+ if (operator === "!") {
2168
+ if (operatorValue === null) {
2169
+ clauses2.push(`${accessor2} ${isNegated ? "IS" : "IS NOT"} NULL`);
2170
+ } else {
2171
+ params.push(operatorValue);
2172
+ const castSuffix2 = getTypeCastSuffix(operatorValue);
2173
+ const castAccessor2 = castSuffix2 ? `(${accessor2})${castSuffix2}` : accessor2;
2174
+ clauses2.push(`${castAccessor2}${isNegated ? "=" : "<>"}$${params.length}`);
2175
+ }
2176
+ } else if (operator === "<" || operator === "<=" || operator === ">" || operator === ">=") {
2177
+ params.push(operatorValue);
2178
+ const castSuffix2 = getTypeCastSuffix(operatorValue);
2179
+ const castAccessor2 = castSuffix2 ? `(${accessor2})${castSuffix2}` : accessor2;
2180
+ const effectiveOperator = isNegated ? negatedComparisonOperators[operator] : operator;
2181
+ clauses2.push(`${castAccessor2}${effectiveOperator}$${params.length}`);
2182
+ }
2183
+ }
2184
+ return clauses2.join(" AND ");
2185
+ }
2186
+ const clauses = [];
2187
+ for (const [nestedKey, nestedValue] of entries) {
2188
+ clauses.push(
2189
+ buildJsonPropertyClause({
2190
+ columnName,
2191
+ path: [...path, nestedKey],
2192
+ isNegated,
2193
+ constraint: nestedValue,
2194
+ params
2195
+ })
2196
+ );
2197
+ }
2198
+ return clauses.join(" AND ");
2199
+ }
2200
+ const accessor = buildJsonAccessor(columnName, path);
2201
+ params.push(constraint);
2202
+ const castSuffix = getTypeCastSuffix(constraint);
2203
+ const castAccessor = castSuffix ? `(${accessor})${castSuffix}` : accessor;
2204
+ return `${castAccessor}${isNegated ? "<>" : "="}$${params.length}`;
2205
+ }
2104
2206
  function buildLikeOperatorStatement({ repositoriesByModelNameLowered, model, propertyName, isNegated, value, params, joins }) {
2105
2207
  return buildArrayOrSingleStatement({
2106
2208
  repositoriesByModelNameLowered,
package/dist/index.d.cts CHANGED
@@ -630,6 +630,7 @@ declare class SubqueryBuilder<T extends Entity, TColumns extends string = never>
630
630
  select(columns: SelectItem<T>[]): SubqueryBuilder<T>;
631
631
  /**
632
632
  * Group the subquery results by one or more columns.
633
+ * @param {(string & keyof T)[]} columns - Columns to group by
633
634
  * @returns New SubqueryBuilder with the groupBy applied
634
635
  * @example
635
636
  * subquery(ProductRepository)
@@ -639,6 +640,7 @@ declare class SubqueryBuilder<T extends Entity, TColumns extends string = never>
639
640
  groupBy(columns: (string & keyof T)[]): SubqueryBuilder<T, TColumns>;
640
641
  /**
641
642
  * Filter groups based on aggregate values (used with groupBy).
643
+ * @param {HavingCondition} condition - Having condition to apply
642
644
  * @returns New SubqueryBuilder with the having condition applied
643
645
  * @example
644
646
  * subquery(ProductRepository)
@@ -1153,7 +1155,10 @@ type ExcludeUndefined<T> = Exclude<T, undefined>;
1153
1155
  type LiteralValues<TValue> = (TValue | null)[] | TValue | null;
1154
1156
  type WhereClauseValue<TValue> = TValue extends NotEntityBrand | undefined ? Exclude<TValue, NotEntityBrand | undefined> : Extract<TValue, Entity> extends undefined ? LiteralValues<ExcludeUndefined<TValue>> : (ExcludeUndefined<Exclude<TValue, Entity>> | null)[] | (Pick<Extract<ExcludeUndefined<TValue>, Entity>, 'id'> | null)[] | ExcludeUndefined<Exclude<TValue, Entity>> | Pick<Extract<ExcludeUndefined<TValue>, Entity>, 'id'> | null;
1155
1157
  type StringConstraint<TValue extends string> = Partial<Record<'contains' | 'endsWith' | 'like' | 'startsWith', LiteralValues<ExcludeUndefined<TValue>>>>;
1156
- type JsonConstraint<TValue> = Partial<Record<'contains', ExcludeUndefined<TValue> | LiteralValues<ExcludeUndefined<TValue>>>>;
1158
+ type JsonPropertyValue = boolean | number | string | null;
1159
+ type JsonConstraint<TValue> = Partial<Record<'contains', ExcludeUndefined<TValue> | LiteralValues<ExcludeUndefined<TValue>>>> & {
1160
+ [key: string]: JsonPropertyValue | JsonPropertyValue[] | Partial<Record<'!' | '<' | '<=' | '>' | '>=', JsonPropertyValue>> | undefined;
1161
+ };
1157
1162
  type NumberOrDateConstraint<TValue extends Date | number> = Partial<Record<'<' | '<=' | '>' | '>=', LiteralValues<ExcludeUndefined<TValue>>>>;
1158
1163
  interface SubqueryInConstraint {
1159
1164
  in: SubqueryBuilderLike;
@@ -1470,4 +1475,4 @@ interface InitializeOptions extends IConnection {
1470
1475
  declare function initialize({ models, pool, readonlyPool, connections, expose }: InitializeOptions): Record<string, IReadonlyRepository<Entity> | IRepository<Entity>>;
1471
1476
 
1472
1477
  export { ColumnBaseMetadata, ColumnCollectionMetadata, ColumnModelMetadata, ColumnTypeMetadata, Entity, ModelMetadata, QueryError, ReadonlyRepository, Repository, ScalarSubquery, SelectBuilder, SubqueryBuilder, column, createDateColumn, getMetadataStorage, initialize, isSubqueryJoin, primaryColumn, subquery, table, updateDateColumn, versionColumn };
1473
- export type { AggregateBuilder, AggregateCallback, AnyJoinInfo, ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateResult, CreateResultArray, CreateResultArrayJSON, CreateResultJSON, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DestroyResultJSON, DestroyResultWithRecords, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindOneResultJSON, FindQueryWithCount, FindQueryWithCountJSON, FindResult, FindResultJSON, FindWithCountResult, GetValueType, HavingComparer, HavingCondition, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, JsonConstraint, LiteralValues, ModelJoinDefinition, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PlainObject, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, SelectAggregateExpression, SelectItem, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, SubqueryJoinDefinition, SubqueryJoinInfo, SubqueryJoinOnCondition, ThroughArgs, TypedAggregateExpression, TypedSelectItem, TypedSubqueryBuilder, UpdateResult, UpdateResultJSON, WhereClauseValue, WhereQuery, WhereQueryStatement };
1478
+ export type { AggregateBuilder, AggregateCallback, AnyJoinInfo, ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateResult, CreateResultArray, CreateResultArrayJSON, CreateResultJSON, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DestroyResultJSON, DestroyResultWithRecords, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindOneResultJSON, FindQueryWithCount, FindQueryWithCountJSON, FindResult, FindResultJSON, FindWithCountResult, GetValueType, HavingComparer, HavingCondition, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, JsonConstraint, JsonPropertyValue, LiteralValues, ModelJoinDefinition, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PlainObject, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, SelectAggregateExpression, SelectItem, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, SubqueryJoinDefinition, SubqueryJoinInfo, SubqueryJoinOnCondition, ThroughArgs, TypedAggregateExpression, TypedSelectItem, TypedSubqueryBuilder, UpdateResult, UpdateResultJSON, WhereClauseValue, WhereQuery, WhereQueryStatement };
package/dist/index.d.mts CHANGED
@@ -630,6 +630,7 @@ declare class SubqueryBuilder<T extends Entity, TColumns extends string = never>
630
630
  select(columns: SelectItem<T>[]): SubqueryBuilder<T>;
631
631
  /**
632
632
  * Group the subquery results by one or more columns.
633
+ * @param {(string & keyof T)[]} columns - Columns to group by
633
634
  * @returns New SubqueryBuilder with the groupBy applied
634
635
  * @example
635
636
  * subquery(ProductRepository)
@@ -639,6 +640,7 @@ declare class SubqueryBuilder<T extends Entity, TColumns extends string = never>
639
640
  groupBy(columns: (string & keyof T)[]): SubqueryBuilder<T, TColumns>;
640
641
  /**
641
642
  * Filter groups based on aggregate values (used with groupBy).
643
+ * @param {HavingCondition} condition - Having condition to apply
642
644
  * @returns New SubqueryBuilder with the having condition applied
643
645
  * @example
644
646
  * subquery(ProductRepository)
@@ -1153,7 +1155,10 @@ type ExcludeUndefined<T> = Exclude<T, undefined>;
1153
1155
  type LiteralValues<TValue> = (TValue | null)[] | TValue | null;
1154
1156
  type WhereClauseValue<TValue> = TValue extends NotEntityBrand | undefined ? Exclude<TValue, NotEntityBrand | undefined> : Extract<TValue, Entity> extends undefined ? LiteralValues<ExcludeUndefined<TValue>> : (ExcludeUndefined<Exclude<TValue, Entity>> | null)[] | (Pick<Extract<ExcludeUndefined<TValue>, Entity>, 'id'> | null)[] | ExcludeUndefined<Exclude<TValue, Entity>> | Pick<Extract<ExcludeUndefined<TValue>, Entity>, 'id'> | null;
1155
1157
  type StringConstraint<TValue extends string> = Partial<Record<'contains' | 'endsWith' | 'like' | 'startsWith', LiteralValues<ExcludeUndefined<TValue>>>>;
1156
- type JsonConstraint<TValue> = Partial<Record<'contains', ExcludeUndefined<TValue> | LiteralValues<ExcludeUndefined<TValue>>>>;
1158
+ type JsonPropertyValue = boolean | number | string | null;
1159
+ type JsonConstraint<TValue> = Partial<Record<'contains', ExcludeUndefined<TValue> | LiteralValues<ExcludeUndefined<TValue>>>> & {
1160
+ [key: string]: JsonPropertyValue | JsonPropertyValue[] | Partial<Record<'!' | '<' | '<=' | '>' | '>=', JsonPropertyValue>> | undefined;
1161
+ };
1157
1162
  type NumberOrDateConstraint<TValue extends Date | number> = Partial<Record<'<' | '<=' | '>' | '>=', LiteralValues<ExcludeUndefined<TValue>>>>;
1158
1163
  interface SubqueryInConstraint {
1159
1164
  in: SubqueryBuilderLike;
@@ -1470,4 +1475,4 @@ interface InitializeOptions extends IConnection {
1470
1475
  declare function initialize({ models, pool, readonlyPool, connections, expose }: InitializeOptions): Record<string, IReadonlyRepository<Entity> | IRepository<Entity>>;
1471
1476
 
1472
1477
  export { ColumnBaseMetadata, ColumnCollectionMetadata, ColumnModelMetadata, ColumnTypeMetadata, Entity, ModelMetadata, QueryError, ReadonlyRepository, Repository, ScalarSubquery, SelectBuilder, SubqueryBuilder, column, createDateColumn, getMetadataStorage, initialize, isSubqueryJoin, primaryColumn, subquery, table, updateDateColumn, versionColumn };
1473
- export type { AggregateBuilder, AggregateCallback, AnyJoinInfo, ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateResult, CreateResultArray, CreateResultArrayJSON, CreateResultJSON, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DestroyResultJSON, DestroyResultWithRecords, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindOneResultJSON, FindQueryWithCount, FindQueryWithCountJSON, FindResult, FindResultJSON, FindWithCountResult, GetValueType, HavingComparer, HavingCondition, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, JsonConstraint, LiteralValues, ModelJoinDefinition, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PlainObject, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, SelectAggregateExpression, SelectItem, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, SubqueryJoinDefinition, SubqueryJoinInfo, SubqueryJoinOnCondition, ThroughArgs, TypedAggregateExpression, TypedSelectItem, TypedSubqueryBuilder, UpdateResult, UpdateResultJSON, WhereClauseValue, WhereQuery, WhereQueryStatement };
1478
+ export type { AggregateBuilder, AggregateCallback, AnyJoinInfo, ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateResult, CreateResultArray, CreateResultArrayJSON, CreateResultJSON, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DestroyResultJSON, DestroyResultWithRecords, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindOneResultJSON, FindQueryWithCount, FindQueryWithCountJSON, FindResult, FindResultJSON, FindWithCountResult, GetValueType, HavingComparer, HavingCondition, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, JsonConstraint, JsonPropertyValue, LiteralValues, ModelJoinDefinition, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PlainObject, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, SelectAggregateExpression, SelectItem, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, SubqueryJoinDefinition, SubqueryJoinInfo, SubqueryJoinOnCondition, ThroughArgs, TypedAggregateExpression, TypedSelectItem, TypedSubqueryBuilder, UpdateResult, UpdateResultJSON, WhereClauseValue, WhereQuery, WhereQueryStatement };
package/dist/index.d.ts CHANGED
@@ -630,6 +630,7 @@ declare class SubqueryBuilder<T extends Entity, TColumns extends string = never>
630
630
  select(columns: SelectItem<T>[]): SubqueryBuilder<T>;
631
631
  /**
632
632
  * Group the subquery results by one or more columns.
633
+ * @param {(string & keyof T)[]} columns - Columns to group by
633
634
  * @returns New SubqueryBuilder with the groupBy applied
634
635
  * @example
635
636
  * subquery(ProductRepository)
@@ -639,6 +640,7 @@ declare class SubqueryBuilder<T extends Entity, TColumns extends string = never>
639
640
  groupBy(columns: (string & keyof T)[]): SubqueryBuilder<T, TColumns>;
640
641
  /**
641
642
  * Filter groups based on aggregate values (used with groupBy).
643
+ * @param {HavingCondition} condition - Having condition to apply
642
644
  * @returns New SubqueryBuilder with the having condition applied
643
645
  * @example
644
646
  * subquery(ProductRepository)
@@ -1153,7 +1155,10 @@ type ExcludeUndefined<T> = Exclude<T, undefined>;
1153
1155
  type LiteralValues<TValue> = (TValue | null)[] | TValue | null;
1154
1156
  type WhereClauseValue<TValue> = TValue extends NotEntityBrand | undefined ? Exclude<TValue, NotEntityBrand | undefined> : Extract<TValue, Entity> extends undefined ? LiteralValues<ExcludeUndefined<TValue>> : (ExcludeUndefined<Exclude<TValue, Entity>> | null)[] | (Pick<Extract<ExcludeUndefined<TValue>, Entity>, 'id'> | null)[] | ExcludeUndefined<Exclude<TValue, Entity>> | Pick<Extract<ExcludeUndefined<TValue>, Entity>, 'id'> | null;
1155
1157
  type StringConstraint<TValue extends string> = Partial<Record<'contains' | 'endsWith' | 'like' | 'startsWith', LiteralValues<ExcludeUndefined<TValue>>>>;
1156
- type JsonConstraint<TValue> = Partial<Record<'contains', ExcludeUndefined<TValue> | LiteralValues<ExcludeUndefined<TValue>>>>;
1158
+ type JsonPropertyValue = boolean | number | string | null;
1159
+ type JsonConstraint<TValue> = Partial<Record<'contains', ExcludeUndefined<TValue> | LiteralValues<ExcludeUndefined<TValue>>>> & {
1160
+ [key: string]: JsonPropertyValue | JsonPropertyValue[] | Partial<Record<'!' | '<' | '<=' | '>' | '>=', JsonPropertyValue>> | undefined;
1161
+ };
1157
1162
  type NumberOrDateConstraint<TValue extends Date | number> = Partial<Record<'<' | '<=' | '>' | '>=', LiteralValues<ExcludeUndefined<TValue>>>>;
1158
1163
  interface SubqueryInConstraint {
1159
1164
  in: SubqueryBuilderLike;
@@ -1470,4 +1475,4 @@ interface InitializeOptions extends IConnection {
1470
1475
  declare function initialize({ models, pool, readonlyPool, connections, expose }: InitializeOptions): Record<string, IReadonlyRepository<Entity> | IRepository<Entity>>;
1471
1476
 
1472
1477
  export { ColumnBaseMetadata, ColumnCollectionMetadata, ColumnModelMetadata, ColumnTypeMetadata, Entity, ModelMetadata, QueryError, ReadonlyRepository, Repository, ScalarSubquery, SelectBuilder, SubqueryBuilder, column, createDateColumn, getMetadataStorage, initialize, isSubqueryJoin, primaryColumn, subquery, table, updateDateColumn, versionColumn };
1473
- export type { AggregateBuilder, AggregateCallback, AnyJoinInfo, ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateResult, CreateResultArray, CreateResultArrayJSON, CreateResultJSON, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DestroyResultJSON, DestroyResultWithRecords, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindOneResultJSON, FindQueryWithCount, FindQueryWithCountJSON, FindResult, FindResultJSON, FindWithCountResult, GetValueType, HavingComparer, HavingCondition, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, JsonConstraint, LiteralValues, ModelJoinDefinition, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PlainObject, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, SelectAggregateExpression, SelectItem, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, SubqueryJoinDefinition, SubqueryJoinInfo, SubqueryJoinOnCondition, ThroughArgs, TypedAggregateExpression, TypedSelectItem, TypedSubqueryBuilder, UpdateResult, UpdateResultJSON, WhereClauseValue, WhereQuery, WhereQueryStatement };
1478
+ export type { AggregateBuilder, AggregateCallback, AnyJoinInfo, ClassLike, ColumnBaseMetadataOptions, ColumnCollectionMetadataOptions, ColumnMetadata, ColumnModelMetadataOptions, ColumnModifierMetadata, ColumnTypeMetadataOptions, Comparer, CountResult, CreateResult, CreateResultArray, CreateResultArrayJSON, CreateResultJSON, CreateUpdateOptions, CreateUpdateParams, DeleteOptions, DestroyResult, DestroyResultJSON, DestroyResultWithRecords, DoNotReturnRecords, EntityFieldValue, EntityPrimitiveOrId, EntityStatic, ExcludeEntityCollections, ExcludeFunctions, FindArgs, FindOneArgs, FindOneResult, FindOneResultJSON, FindQueryWithCount, FindQueryWithCountJSON, FindResult, FindResultJSON, FindWithCountResult, GetValueType, HavingComparer, HavingCondition, IConnection, IReadonlyRepository, IRepository, IRepositoryOptions, IncludeFunctions, InitializeOptions, IsValueOfType, JoinDefinition, JoinInfo, JoinType, JoinedSort, JoinedWhereQuery, JsonConstraint, JsonPropertyValue, LiteralValues, ModelJoinDefinition, ModelMetadataOptions, ModelRelationshipKeys, MultipleSortString, NegatableConstraint, NotEntity, NotEntityBrand, NumberOrDateConstraint, NumberOrDateConstraintWithSubquery, OmitEntityCollections, OmitFunctions, OrderBy, PaginateOptions, PickAsType, PickByValueType, PickFunctions, PlainObject, PoolLike, PoolQueryResult, PopulateArgs, Populated, QueryResult, QueryResultOptionalPopulated, QueryResultPopulated, QueryResultRow, ReturnSelect$1 as ReturnSelect, ScalarSubqueryConstraint, SelectAggregateExpression, SelectItem, Sort, SortObject, SortObjectValue, SortString, StringConstraint, SubqueryBuilderLike, SubqueryInConstraint, SubqueryJoinDefinition, SubqueryJoinInfo, SubqueryJoinOnCondition, ThroughArgs, TypedAggregateExpression, TypedSelectItem, TypedSubqueryBuilder, UpdateResult, UpdateResultJSON, WhereClauseValue, WhereQuery, WhereQueryStatement };
package/dist/index.mjs CHANGED
@@ -457,6 +457,7 @@ class SubqueryBuilder {
457
457
  }
458
458
  /**
459
459
  * Group the subquery results by one or more columns.
460
+ * @param {(string & keyof T)[]} columns - Columns to group by
460
461
  * @returns New SubqueryBuilder with the groupBy applied
461
462
  * @example
462
463
  * subquery(ProductRepository)
@@ -470,6 +471,7 @@ class SubqueryBuilder {
470
471
  }
471
472
  /**
472
473
  * Filter groups based on aggregate values (used with groupBy).
474
+ * @param {HavingCondition} condition - Having condition to apply
473
475
  * @returns New SubqueryBuilder with the having condition applied
474
476
  * @example
475
477
  * subquery(ProductRepository)
@@ -1735,6 +1737,21 @@ function buildWhere({
1735
1737
  let subQueryComparer;
1736
1738
  if (isComparer(key)) {
1737
1739
  subQueryComparer = key;
1740
+ } else if (propertyName) {
1741
+ const parentColumn = model.columnsByPropertyName[propertyName];
1742
+ if (parentColumn?.type?.toLowerCase() === "json") {
1743
+ andValues.push(
1744
+ buildJsonPropertyClause({
1745
+ columnName: parentColumn.name,
1746
+ path: [key],
1747
+ isNegated,
1748
+ constraint: where,
1749
+ params
1750
+ })
1751
+ );
1752
+ continue;
1753
+ }
1754
+ propertyName = key;
1738
1755
  } else {
1739
1756
  propertyName = key;
1740
1757
  }
@@ -2099,6 +2116,91 @@ function buildJsonContainmentStatement({ repositoriesByModelNameLowered, model,
2099
2116
  }
2100
2117
  });
2101
2118
  }
2119
+ function getTypeCastSuffix(value) {
2120
+ if (typeof value === "number") {
2121
+ return "::numeric";
2122
+ }
2123
+ if (typeof value === "boolean") {
2124
+ return "::boolean";
2125
+ }
2126
+ return "";
2127
+ }
2128
+ function buildJsonAccessor(columnName, path) {
2129
+ let result = `"${columnName}"`;
2130
+ for (let i = 0; i < path.length; i++) {
2131
+ const arrow = i === path.length - 1 ? "->>" : "->";
2132
+ result += `${arrow}'${path[i]}'`;
2133
+ }
2134
+ return result;
2135
+ }
2136
+ function isJsonConstraintOperator(key) {
2137
+ return key === "!" || key === "<" || key === "<=" || key === ">" || key === ">=";
2138
+ }
2139
+ function buildJsonPropertyClause({
2140
+ columnName,
2141
+ path,
2142
+ isNegated,
2143
+ constraint,
2144
+ params
2145
+ }) {
2146
+ for (const segment of path) {
2147
+ assertValidSqlIdentifier(segment, `JSON property name "${segment}"`);
2148
+ }
2149
+ if (constraint === null) {
2150
+ return `${buildJsonAccessor(columnName, path)} ${isNegated ? "IS NOT" : "IS"} NULL`;
2151
+ }
2152
+ if (Array.isArray(constraint)) {
2153
+ const accessor2 = buildJsonAccessor(columnName, path);
2154
+ params.push(constraint);
2155
+ return `${accessor2}${isNegated ? "<>ALL" : "=ANY"}($${params.length})`;
2156
+ }
2157
+ if (typeof constraint === "object") {
2158
+ const entries = Object.entries(constraint);
2159
+ const firstKey = entries[0]?.[0];
2160
+ if (firstKey && isJsonConstraintOperator(firstKey)) {
2161
+ const accessor2 = buildJsonAccessor(columnName, path);
2162
+ const negatedComparisonOperators = { "<": ">=", "<=": ">", ">": "<=", ">=": "<" };
2163
+ const clauses2 = [];
2164
+ for (const [operator, operatorValue] of entries) {
2165
+ if (operator === "!") {
2166
+ if (operatorValue === null) {
2167
+ clauses2.push(`${accessor2} ${isNegated ? "IS" : "IS NOT"} NULL`);
2168
+ } else {
2169
+ params.push(operatorValue);
2170
+ const castSuffix2 = getTypeCastSuffix(operatorValue);
2171
+ const castAccessor2 = castSuffix2 ? `(${accessor2})${castSuffix2}` : accessor2;
2172
+ clauses2.push(`${castAccessor2}${isNegated ? "=" : "<>"}$${params.length}`);
2173
+ }
2174
+ } else if (operator === "<" || operator === "<=" || operator === ">" || operator === ">=") {
2175
+ params.push(operatorValue);
2176
+ const castSuffix2 = getTypeCastSuffix(operatorValue);
2177
+ const castAccessor2 = castSuffix2 ? `(${accessor2})${castSuffix2}` : accessor2;
2178
+ const effectiveOperator = isNegated ? negatedComparisonOperators[operator] : operator;
2179
+ clauses2.push(`${castAccessor2}${effectiveOperator}$${params.length}`);
2180
+ }
2181
+ }
2182
+ return clauses2.join(" AND ");
2183
+ }
2184
+ const clauses = [];
2185
+ for (const [nestedKey, nestedValue] of entries) {
2186
+ clauses.push(
2187
+ buildJsonPropertyClause({
2188
+ columnName,
2189
+ path: [...path, nestedKey],
2190
+ isNegated,
2191
+ constraint: nestedValue,
2192
+ params
2193
+ })
2194
+ );
2195
+ }
2196
+ return clauses.join(" AND ");
2197
+ }
2198
+ const accessor = buildJsonAccessor(columnName, path);
2199
+ params.push(constraint);
2200
+ const castSuffix = getTypeCastSuffix(constraint);
2201
+ const castAccessor = castSuffix ? `(${accessor})${castSuffix}` : accessor;
2202
+ return `${castAccessor}${isNegated ? "<>" : "="}$${params.length}`;
2203
+ }
2102
2204
  function buildLikeOperatorStatement({ repositoriesByModelNameLowered, model, propertyName, isNegated, value, params, joins }) {
2103
2205
  return buildArrayOrSingleStatement({
2104
2206
  repositoriesByModelNameLowered,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bigal",
3
- "version": "15.10.2",
3
+ "version": "15.11.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",
@@ -38,31 +38,33 @@
38
38
  "@semantic-release/commit-analyzer": "13.0.1",
39
39
  "@semantic-release/git": "10.0.1",
40
40
  "@semantic-release/github": "12.0.6",
41
- "@semantic-release/npm": "13.1.4",
41
+ "@semantic-release/npm": "13.1.5",
42
42
  "@semantic-release/release-notes-generator": "14.1.0",
43
43
  "@types/node": ">=22",
44
- "eslint": "10.0.2",
45
- "eslint-config-decent": "4.1.0",
44
+ "@typescript/native-preview": "7.0.0-dev.20260310.1",
46
45
  "husky": "9.1.7",
47
- "lint-staged": "16.2.7",
48
- "markdownlint-cli": "0.47.0",
46
+ "lint-staged": "16.3.3",
47
+ "markdownlint-cli": "0.48.0",
49
48
  "npm-run-all2": "8.0.4",
49
+ "oxfmt": "0.37.0",
50
+ "oxlint": "1.52.0",
51
+ "oxlint-tsgolint": "0.16.0",
50
52
  "pinst": "3.0.0",
51
- "prettier": "3.8.1",
53
+ "postgres-pool": "11.0.4",
52
54
  "semantic-release": "25.0.3",
53
55
  "strict-event-emitter-types": "2.0.0",
54
- "postgres-pool": "11.0.3",
55
56
  "typescript": "5.9.3",
56
57
  "unbuild": "3.6.1",
57
58
  "vitest": "4.0.18"
58
59
  },
59
60
  "scripts": {
60
61
  "build": "unbuild",
61
- "check:types": "tsc --noEmit --skipLibCheck",
62
+ "check:types": "tsgo --noEmit --skipLibCheck",
62
63
  "test": "npm run check:types && vitest run",
63
- "lint:markdown": "prettier --write '**/*.md' '!**/node_modules/**' '!**/dist/**' && markdownlint '**/*.md' --ignore '**/node_modules/**' --ignore '**/dist/**' --config=.github/linters/.markdown-lint.yml --fix",
64
- "lint:code": "eslint --fix",
65
- "lint": "run-p lint:*",
64
+ "lint:markdown": "markdownlint '**/*.md' --ignore '**/node_modules/**' --ignore '**/dist/**' --config=.github/linters/.markdown-lint.yml --fix",
65
+ "lint:code": "oxlint --fix --deny-warnings",
66
+ "lint": "npm run format && run-p lint:*",
67
+ "format": "oxfmt --write .",
66
68
  "lint-staged": "lint-staged",
67
69
  "beta": "npm publish --tag beta",
68
70
  "prepublishOnly": "pinst --disable",
@@ -71,14 +73,15 @@
71
73
  },
72
74
  "lint-staged": {
73
75
  "*.md": [
74
- "prettier --write --cache",
76
+ "oxfmt --write",
75
77
  "markdownlint --config=.github/linters/.markdown-lint.yml --fix"
76
78
  ],
77
79
  "*.{js,cjs,mjs,ts}": [
78
- "eslint --fix"
80
+ "oxfmt --write",
81
+ "oxlint --fix --deny-warnings"
79
82
  ],
80
83
  "*.{json5,yml}": [
81
- "prettier --write"
84
+ "oxfmt --write"
82
85
  ]
83
86
  },
84
87
  "repository": {
package/.prettierrc.cjs DELETED
@@ -1,34 +0,0 @@
1
- 'use strict';
2
-
3
- module.exports = {
4
- arrowParens: 'always',
5
- bracketSpacing: true,
6
- printWidth: 200,
7
- quoteProps: 'as-needed',
8
- semi: true,
9
- singleQuote: true,
10
- useTabs: false,
11
- tabWidth: 2,
12
- trailingComma: 'all',
13
-
14
- overrides: [
15
- {
16
- files: ['*.js', '*.cjs', '*.mjs'],
17
- options: {
18
- parser: 'espree',
19
- },
20
- },
21
- {
22
- files: '*.json',
23
- options: {
24
- parser: 'json',
25
- },
26
- },
27
- {
28
- files: '*.ts',
29
- options: {
30
- parser: 'typescript',
31
- },
32
- },
33
- ],
34
- };
package/eslint.config.mjs DELETED
@@ -1,14 +0,0 @@
1
- import { config } from 'eslint-config-decent';
2
-
3
- export default [
4
- ...config({
5
- tsconfigRootDir: import.meta.dirname,
6
- enableTestingLibrary: false,
7
- }),
8
- {
9
- files: ['**/*.ts'],
10
- rules: {
11
- '@typescript-eslint/no-invalid-void-type': 'off',
12
- },
13
- },
14
- ];