Skip to content

fix!: harden v2 beta release - #763

Merged
tada5hi merged 6 commits into
masterfrom
fix/v2-beta-release-hardening
Jul 15, 2026
Merged

fix!: harden v2 beta release#763
tada5hi merged 6 commits into
masterfrom
fix/v2-beta-release-hardening

Conversation

@tada5hi

@tada5hi tada5hi commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • Harden parser validation, nested object expansion, expression tokenization, regex handling, and SQL dialect behavior.
  • Preserve caller-owned TypeORM predicates and make relation aliases collision-proof.
  • Prepare all ten public packages for a synchronized 2.0.0-beta.0 release.
  • Gate publishing on build, lint, tests, and coverage, and add current MIT license metadata.
  • Update user and agent documentation for the changed behavior.

Breaking change

Generated relation aliases now use length-prefixed path segments so distinct relation paths cannot collide.

Verification

  • npm run lint
  • npm run build
  • npm run test — 881 tests
  • npm run test:coverage
  • npm audit --omit=dev --json — 0 production vulnerabilities
  • npm package tarball inspection for all ten public packages

Release follow-up

After merge, refresh the existing release-please PR and verify that it proposes all ten packages at 2.0.0-beta.0. Remove the one-time release-as override after the first beta is published.

Summary by CodeRabbit

  • New Features
    • Added asynchronous parsing, URL encoding, and decoding APIs for queries and filters.
    • Async schema validation can transform or reject individual filters while preserving compound expressions; defaults apply when all filters are rejected.
    • Added support for regex string patterns with validation and clearer database-specific rendering.
  • Bug Fixes
    • TypeORM filters now preserve existing query conditions instead of replacing them.
    • Relation aliases are collision-resistant and consistent across joins, fields, filters, and sorting.
  • Documentation
    • Updated usage, migration, validation, and release guidance for the beta release.

Preserve existing TypeORM predicates, validate parser filters, reject malformed expression input, and correct SQL regex/dialect behavior.

Prepare all public workspaces for synchronized beta publishing and add package license metadata.

BREAKING CHANGE: relation aliases now use length-prefixed path segments to avoid collisions.
Copilot AI review requested due to automatic review settings July 14, 2026 20:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This change adds asynchronous parser and URL codec APIs, schema-aware filter validation, expression parser hardening, deterministic SQL relation aliases, regex rendering updates, TypeORM predicate preservation, and beta release/package configuration.

Changes

Async parsing and codec flow

Layer / File(s) Summary
Filter validation contracts
packages/core/src/parser/parameter/filters/*, packages/core/src/errors/*
Filter leaves can be accepted, replaced, or rejected while compound structure is preserved; synchronous paths reject promise-based validators and async paths await them sequentially.
Parser async orchestration
packages/core/src/parser/*, packages/parser-simple/..., packages/parser-expression/..., packages/parser-mongo/...
Parsers gain async entry points, schema validation, default fallback behavior, expression token validation, and recursion limits.
Async URL codec pipeline
packages/codec-url*/src/*, packages/codec-url/src/*
Encoders, decoders, and the registry add async methods, with registry fallback to synchronous codec hooks.

SQL and TypeORM behavior

Layer / File(s) Summary
SQL aliases and regex rendering
packages/sql/src/*, packages/memory/src/*
Relation aliases use length-prefixed segments; regex strings are supported and rendered using PostgreSQL- and Oracle-specific syntax.
TypeORM predicate and relation integration
packages/typeorm/src/*
Generated filter SQL is appended with AND, existing predicates are preserved, and relation joins use deterministic aliases.

Beta release and package metadata

Layer / File(s) Summary
Beta release workflow
release-please-config.json, .release-please-manifest.json, .github/workflows/release.yml, package.json, nx.json
Release automation tracks explicit linked beta workspaces and runs lint, coverage, upload, and publish steps.
Package publication metadata
packages/*/package.json, packages/*/LICENSE, LICENSE
Packages receive public beta publish settings, repository metadata corrections, and MIT license files.
Architecture and migration documentation
.agents/*, packages/docs/*
Documentation describes async validation, aliasing, TypeORM behavior, regex handling, and beta release conventions.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: hardening the v2 beta release across validation, packaging, docs, and release workflow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/v2-beta-release-hardening

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/schema/parameter/filters/types.ts`:
- Around line 10-15: Reject asynchronous validator results at runtime to
preserve the synchronous Validator contract: update
packages/core/src/schema/parameter/filters/types.ts lines 10-15 and
packages/core/src/schema/parameter/filters/schema.ts lines 60-65 so
schema.validate detects Promise results and throws before they enter the filter
tree; update packages/core/src/parser/parameter/filters/validate.ts around line
38 to propagate that rejection rather than accepting the returned value.

In `@packages/typeorm/src/adapter/filters.ts`:
- Around line 150-155: Update TypeormAdapter.execute() and the filter-building
flow around queryBuilder.andWhere(sql, params) so repeated executions do not
accumulate adapter-owned predicates on a reused QueryBuilder. Reset or replace
only the adapter-owned WHERE fragment before applying new filters, while
preserving any application-owned baseline predicate already present on the
builder.

In `@packages/typeorm/test/unit/adapter/module.spec.ts`:
- Around line 91-102: Update the assertion in the empty-query test around
TypeormAdapter.execute to expect the configured driver’s parameter placeholder
syntax rather than the literal value 1, while continuing to verify that the
caller-owned where clause is preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 74fe824a-2ab9-4485-bcfc-6640b11aa144

📥 Commits

Reviewing files that changed from the base of the PR and between 5821c59 and 0065889.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (67)
  • .agents/architecture.md
  • .agents/conventions.md
  • .agents/migration-notes.md
  • .agents/references/typeorm-extension.md
  • .agents/references/typeorm.md
  • .github/workflows/release.yml
  • .release-please-manifest.json
  • LICENSE
  • package.json
  • packages/codec-url-expression/LICENSE
  • packages/codec-url-expression/package.json
  • packages/codec-url-simple/LICENSE
  • packages/codec-url-simple/package.json
  • packages/codec-url/LICENSE
  • packages/codec-url/package.json
  • packages/core/LICENSE
  • packages/core/package.json
  • packages/core/src/parameter/filters/record/types.ts
  • packages/core/src/parser/base.ts
  • packages/core/src/parser/parameter/filters/index.ts
  • packages/core/src/parser/parameter/filters/validate.ts
  • packages/core/src/schema/parameter/filters/schema.ts
  • packages/core/src/schema/parameter/filters/types.ts
  • packages/core/test/unit/parameter/filters-validation.spec.ts
  • packages/docs/guide/executing-queries.md
  • packages/docs/guide/filters.md
  • packages/docs/guide/migration-typeorm-extension.md
  • packages/docs/package.json
  • packages/docs/packages/sql.md
  • packages/docs/packages/typeorm.md
  • packages/memory/LICENSE
  • packages/memory/package.json
  • packages/memory/src/parameter/filters/compiler.ts
  • packages/parser-expression/LICENSE
  • packages/parser-expression/package.json
  • packages/parser-expression/src/parameter/filters/constants.ts
  • packages/parser-expression/src/parameter/filters/module.ts
  • packages/parser-expression/test/unit/parser/filters.spec.ts
  • packages/parser-mongo/LICENSE
  • packages/parser-mongo/package.json
  • packages/parser-mongo/src/parameter/filters/module.ts
  • packages/parser-mongo/test/unit/parser/filters.spec.ts
  • packages/parser-simple/LICENSE
  • packages/parser-simple/package.json
  • packages/parser-simple/src/parameter/filters/module.ts
  • packages/parser-simple/test/unit/parser/filters.spec.ts
  • packages/sql/LICENSE
  • packages/sql/package.json
  • packages/sql/src/adapter/module.ts
  • packages/sql/src/adapter/relations/base.ts
  • packages/sql/src/adapter/relations/types.ts
  • packages/sql/src/dialect/oracle.ts
  • packages/sql/src/dialect/pg.ts
  • packages/sql/src/helpers/relation-alias.ts
  • packages/sql/src/visitor/filters.ts
  • packages/sql/test/unit/adapter.spec.ts
  • packages/sql/test/unit/interpreters/elem-match.spec.ts
  • packages/sql/test/unit/interpreters/regex.spec.ts
  • packages/sql/test/unit/interpreters/relation-nested.spec.ts
  • packages/sql/test/unit/interpreters/relation.spec.ts
  • packages/typeorm/LICENSE
  • packages/typeorm/package.json
  • packages/typeorm/src/adapter/filters.ts
  • packages/typeorm/test/unit/acceptance.spec.ts
  • packages/typeorm/test/unit/adapter/module.spec.ts
  • packages/typeorm/test/unit/adapter/relations.spec.ts
  • release-please-config.json

Comment thread packages/core/src/schema/parameter/filters/types.ts Outdated
Comment on lines +150 to +155
if (sql) {
// The builder may already carry an application-owned predicate
// (for example a tenant or authorization scope). Rapiq filters
// narrow that query; they must never replace its baseline WHERE.
this.queryBuilder.andWhere(sql, params);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail

# Map the file and inspect the relevant area first.
ast-grep outline packages/typeorm/src/adapter/filters.ts --view expanded || true

echo '--- file excerpt ---'
sed -n '1,260p' packages/typeorm/src/adapter/filters.ts

echo '--- search for queryBuilder reuse/reset ---'
rg -n "queryBuilder|andWhere\(|where\(|filters.ts|new .*QueryBuilder|createQueryBuilder" packages/typeorm/src -S

Repository: tada5hi/rapiq

Length of output: 10140


🏁 Script executed:

set -euo pipefail

# Narrow search to how this adapter instance is constructed and reused.
rg -n "class .*Adapter|extends .*Adapter|filters.ts|applyFilters|filter" packages/typeorm/src -S

# Inspect nearby files if referenced.
fd -a ".*adapter.*\.ts$" packages/typeorm/src

Repository: tada5hi/rapiq

Length of output: 1420


🏁 Script executed:

set -euo pipefail

# Show the relevant file with line numbers and any surrounding helpers.
cat -n packages/typeorm/src/adapter/filters.ts | sed -n '1,260p'

# Find where this adapter method is called.
rg -n "filters\.ts|apply.*filter|build.*filter|queryBuilder\.andWhere|queryBuilder\.where" packages/typeorm/src -S

Repository: tada5hi/rapiq

Length of output: 5797


🏁 Script executed:

set -euo pipefail

python3 - <<'PY'
from pathlib import Path
import re

root = Path("packages/typeorm/src")
targets = ["queryBuilder", "andWhere(", "where("]
for path in root.rglob("*.ts"):
    text = path.read_text()
    if any(t in text for t in targets):
        print(f"\n## {path}")
        for i, line in enumerate(text.splitlines(), 1):
            if any(t in line for t in targets):
                print(f"{i}: {line}")
PY

Repository: tada5hi/rapiq

Length of output: 3294


🏁 Script executed:

set -euo pipefail

# Inspect the root adapter flow and the base filter state management.
sed -n '1,220p' packages/typeorm/src/adapter/module.ts

echo '--- search base adapter implementation ---'
rg -n "class FiltersBaseAdapter|clear\(\)|getQueryAndParameters|setChildAttributes|execute\(" . -S

# If the base implementation is vendored in the repo, inspect it too.
fd -a "filters.*\.ts$|base.*adapter.*\.ts$|adapter.*\.ts$" .

Repository: tada5hi/rapiq

Length of output: 25209


Avoid appending onto a reused QueryBuilder. TypeormAdapter.execute() clears adapter state, but not the underlying TypeORM builder, so andWhere(sql, params) will accumulate duplicate predicates on repeated calls. Preserve the baseline scope, but reset or replace the adapter-owned WHERE fragment before reapplying filters.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/typeorm/src/adapter/filters.ts` around lines 150 - 155, Update
TypeormAdapter.execute() and the filter-building flow around
queryBuilder.andWhere(sql, params) so repeated executions do not accumulate
adapter-owned predicates on a reused QueryBuilder. Reset or replace only the
adapter-owned WHERE fragment before applying new filters, while preserving any
application-owned baseline predicate already present on the builder.

Source: Learnings

Comment on lines +91 to 102
it('should preserve a caller-owned where clause for an empty query', () => {
const queryBuilder = dataSource
.getRepository(User)
.createQueryBuilder('user')
.where('user.id = :actorId', { actorId: 1 });

const adapter = new TypeormAdapter({ queryBuilder });

adapter.execute(new Query());
expect(queryBuilder.getSql()).not.toContain('WHERE');

expect(queryBuilder.getSql()).toContain('WHERE "user"."id" = 1');
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the TypeORM SQL string assertion for the empty query test.

Similarly, queryBuilder.getSql() will not return the literal value 1 for the caller-owned condition. It will return the placeholder syntax for the configured driver.

🐛 Proposed fix
-    it('should preserve a caller-owned where clause for an empty query', () => {
+    it('should preserve a caller-owned where clause for an empty query', () => {
         const queryBuilder = dataSource
             .getRepository(User)
             .createQueryBuilder('user')
             .where('user.id = :actorId', { actorId: 1 });
 
         const adapter = new TypeormAdapter({ queryBuilder });
 
         adapter.execute(new Query());
 
-        expect(queryBuilder.getSql()).toContain('WHERE "user"."id" = 1');
+        const [sql, params] = queryBuilder.getQueryAndParameters();
+        expect(sql).toMatch(/WHERE "user"\."id" = (\?|\$1|:actorId)/);
+        expect(params).toEqual(expect.arrayContaining([1]));
     });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
it('should preserve a caller-owned where clause for an empty query', () => {
const queryBuilder = dataSource
.getRepository(User)
.createQueryBuilder('user')
.where('user.id = :actorId', { actorId: 1 });
const adapter = new TypeormAdapter({ queryBuilder });
adapter.execute(new Query());
expect(queryBuilder.getSql()).not.toContain('WHERE');
expect(queryBuilder.getSql()).toContain('WHERE "user"."id" = 1');
});
it('should preserve a caller-owned where clause for an empty query', () => {
const queryBuilder = dataSource
.getRepository(User)
.createQueryBuilder('user')
.where('user.id = :actorId', { actorId: 1 });
const adapter = new TypeormAdapter({ queryBuilder });
adapter.execute(new Query());
const [sql, params] = queryBuilder.getQueryAndParameters();
expect(sql).toMatch(/WHERE "user"\."id" = (\?|\$1|:actorId)/);
expect(params).toEqual(expect.arrayContaining([1]));
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/typeorm/test/unit/adapter/module.spec.ts` around lines 91 - 102,
Update the assertion in the empty-query test around TypeormAdapter.execute to
expect the configured driver’s parameter placeholder syntax rather than the
literal value 1, while continuing to verify that the caller-owned where clause
is preserved.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/core/src/schema/parameter/filters/schema.ts`:
- Around line 75-78: Update the promise-handling branch around
this.options.validate(input) and isPromiseLike(output) to attach a no-op
rejection handler to output before throwing
SchemaError.validatorAsyncUnsupported(). Add a regression test covering a
validator that returns a rejected promise, ensuring the synchronous validation
path throws the expected SchemaError without an unhandled rejection.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1ff1d2d5-aa96-45c9-b5df-f9aecebd0ac4

📥 Commits

Reviewing files that changed from the base of the PR and between 0065889 and 6a2218e.

📒 Files selected for processing (7)
  • .agents/architecture.md
  • packages/core/src/errors/code.ts
  • packages/core/src/errors/schema.ts
  • packages/core/src/schema/parameter/filters/schema.ts
  • packages/core/test/unit/parameter/filters-validation.spec.ts
  • packages/docs/guide/errors.md
  • packages/docs/guide/filters.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/core/test/unit/parameter/filters-validation.spec.ts
  • .agents/architecture.md
  • packages/docs/guide/filters.md

Comment thread packages/core/src/schema/parameter/filters/schema.ts Outdated
@tada5hi

tada5hi commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai pause

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews paused.

tada5hi added 3 commits July 15, 2026 10:00
Add explicit async parser and codec entry points while keeping synchronous methods deterministic. Preserve sync-only custom codec compatibility and document both execution paths.
@tada5hi

tada5hi commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
packages/typeorm/src/adapter/filters.ts (1)

150-155: 🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Prevent accumulating duplicate adapter-owned predicates on repeated executions.

Using andWhere correctly preserves the application's baseline predicates (like tenant or authorization scopes). However, as flagged in a previous review, if this adapter is executed multiple times on the same QueryBuilder, andWhere will accumulate duplicate predicates because the previous run's adapter-owned WHERE fragment is never removed.

To resolve this while preserving the baseline, consider tracking the applied adapter condition (e.g., keeping a reference to the specific WHERE clause in expressionMap.wheres) and selectively removing it before appending the new filters on subsequent runs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/typeorm/src/adapter/filters.ts` around lines 150 - 155, Update the
filter application logic in the adapter method containing this sql block to
remove the previously applied adapter-owned WHERE entry from the query builder’s
expressionMap.wheres before adding the new condition. Preserve all
application-owned predicates, then append the current filters with andWhere so
repeated executions replace only the adapter fragment rather than accumulating
duplicates.
🧹 Nitpick comments (3)
packages/parser-simple/src/parameter/filters/module.ts (1)

78-87: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider parallelizing asynchronous filter validations.

Evaluating conditions in a for...of loop creates an asynchronous execution waterfall. Since conditions are mutually independent during validation, you can safely use Promise.all to validate them concurrently, which can notably improve throughput if schema validation delegates to database queries or external services.

🚀 Proposed refactor to use `Promise.all`
-        let items: ICondition[] = [];
         const parsed = this.run(input, scope);
 
-        for (const item of parsed) {
-            const validated = await applyFiltersSchemaValidationAsync(item, scope.schema);
-            if (validated) {
-                items.push(validated);
-            }
-        }
+        const validatedItems = await Promise.all(
+            parsed.map((item) => applyFiltersSchemaValidationAsync(item, scope.schema))
+        );
+
+        let items: ICondition[] = validatedItems.filter(
+            (item): item is ICondition => typeof item !== 'undefined'
+        );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/parser-simple/src/parameter/filters/module.ts` around lines 78 - 87,
Update the validation loop in the filter parsing method around run and
applyFiltersSchemaValidationAsync to execute independent validations
concurrently with Promise.all, then retain only successful validated results in
items while preserving the existing result ordering and filtering behavior.
packages/parser-expression/test/unit/parser/filters.spec.ts (1)

179-191: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Redundant double-parse in error-code assertions.

Both tests parse the same input twice — once for toThrow(FiltersParseError), once more in a try/catch just to read .code. toThrow can match on error shape directly, avoiding the second parse.

♻️ Proposed simplification
     ])('should reject unmatched source characters in %s', (input) => {
-        expect(() => parser.parseExact(input)).toThrow(FiltersParseError);
-
-        try {
-            parser.parseExact(input);
-        } catch (error) {
-            expect((error as FiltersParseError).code).toEqual(ErrorCode.SYNTAX_INVALID);
-        }
+        expect(() => parser.parseExact(input)).toThrow(
+            expect.objectContaining({ code: ErrorCode.SYNTAX_INVALID }),
+        );
     });

Same pattern applies to the excessive-nesting test at Lines 193-204.

Also applies to: 193-204

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/parser-expression/test/unit/parser/filters.spec.ts` around lines 179
- 191, Update the unmatched-source-character and excessive-nesting tests to
parse each input only once, using the assertion framework to verify both the
thrown FiltersParseError type and its ErrorCode.SYNTAX_INVALID code directly.
Remove the redundant try/catch and second parser.parseExact invocation while
preserving the existing test cases.
packages/parser-expression/src/parameter/filters/module.ts (1)

56-105: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Sync/async paths duplicate scope-resolution and null/EOF handling.

parse()/parseAsync() (Lines 63-70 vs 87-94) and parseExact()/parseExactAsync() (Lines 111-134 vs 154-177) are near-identical except for the sync vs async validation call. This is a real drift risk in a hardening-focused PR: a future fix to scope resolution, the EOF check, or the defaults fallback could easily be applied to only one of the two paths.

Consider extracting the shared logic (scope resolution, tokenize+EOF check, defaults construction) into a private helper reused by both sync and async entry points, with only the validation call diverging.

♻️ Sketch of a shared helper
+    private parseTokens(
+        input: string,
+        options: FiltersParseOptions,
+    ) : { expr: Filters | Filter, scope?: FiltersScope } {
+        this.pos = 0;
+        this.tokens = this.tokenize(input);
+
+        let scope : FiltersScope | undefined;
+        if (options.schema || options.strict) {
+            scope = ResolutionScope.for(this.registry, Parameter.FILTERS, options.schema, {
+                relations: options.relations,
+                throwOnFailure: true,
+                strict: options.strict,
+            }) as FiltersScope;
+        }
+
+        const expr = this.parseFilterExpression(scope);
+        if (this.peek().type !== FilterTokenType.EOF) {
+            throw FiltersParseError.syntaxInvalid(`Unexpected token: ${this.peek().type}`);
+        }
+
+        return { expr, scope };
+    }
+
     parseExact<RECORD extends ObjectLiteral = ObjectLiteral>(
         input: unknown,
         options: FiltersParseOptions<RECORD> = {},
     ) : IFilters | IFilter {
         if (typeof input !== 'string') {
             throw FiltersParseError.inputInvalid();
         }
 
-        this.pos = 0;
-        this.tokens = this.tokenize(input);
-        ...
+        const { expr, scope } = this.parseTokens(input, options);
 
         if (!scope) {
             return expr;
         }
 
         const validated = applyFiltersSchemaValidation(expr, scope.schema);
         ...

Also applies to: 107-188

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/parser-expression/src/parameter/filters/module.ts` around lines 56 -
105, Refactor the duplicated handling in parse(), parseAsync(), parseExact(),
and parseExactAsync() into private shared helpers for scope resolution, null/EOF
handling, and defaults construction, while keeping only the synchronous versus
asynchronous validation call separate. Ensure both entry points preserve
identical behavior for absent input, tokenization, EOF checks, and fallback
filter construction.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/sql/src/visitor/filters.ts`:
- Around line 150-168: Update visitFilterRegex to stop constructing JavaScript
RegExp instances for string patterns; pass expr.value directly to the database
adapter and use ignoreCase=false for strings while preserving RegExp handling
and its flags. Remove the unit test expecting AdapterError for invalid string
patterns and revise the SQL documentation so string pattern validation/errors
are delegated to the database.

In `@packages/typeorm/test/unit/adapter/module.spec.ts`:
- Around line 86-88: Update the SQL assertions in
packages/typeorm/test/unit/adapter/module.spec.ts at lines 86-88 and 101 to use
queryBuilder.getQueryAndParameters(). At lines 86-88, assert the generated SQL
uses parameter placeholders for both user.id and user.age, and verify the
returned parameters contain 1 and 18; at line 101, assert the user.id
placeholder and verify the parameters contain 1.

---

Duplicate comments:
In `@packages/typeorm/src/adapter/filters.ts`:
- Around line 150-155: Update the filter application logic in the adapter method
containing this sql block to remove the previously applied adapter-owned WHERE
entry from the query builder’s expressionMap.wheres before adding the new
condition. Preserve all application-owned predicates, then append the current
filters with andWhere so repeated executions replace only the adapter fragment
rather than accumulating duplicates.

---

Nitpick comments:
In `@packages/parser-expression/src/parameter/filters/module.ts`:
- Around line 56-105: Refactor the duplicated handling in parse(), parseAsync(),
parseExact(), and parseExactAsync() into private shared helpers for scope
resolution, null/EOF handling, and defaults construction, while keeping only the
synchronous versus asynchronous validation call separate. Ensure both entry
points preserve identical behavior for absent input, tokenization, EOF checks,
and fallback filter construction.

In `@packages/parser-expression/test/unit/parser/filters.spec.ts`:
- Around line 179-191: Update the unmatched-source-character and
excessive-nesting tests to parse each input only once, using the assertion
framework to verify both the thrown FiltersParseError type and its
ErrorCode.SYNTAX_INVALID code directly. Remove the redundant try/catch and
second parser.parseExact invocation while preserving the existing test cases.

In `@packages/parser-simple/src/parameter/filters/module.ts`:
- Around line 78-87: Update the validation loop in the filter parsing method
around run and applyFiltersSchemaValidationAsync to execute independent
validations concurrently with Promise.all, then retain only successful validated
results in items while preserving the existing result ordering and filtering
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8e3aee13-0526-464c-9e8d-6e325fa23f92

📥 Commits

Reviewing files that changed from the base of the PR and between 5821c59 and 9824164.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (92)
  • .agents/architecture.md
  • .agents/conventions.md
  • .agents/migration-notes.md
  • .agents/references/typeorm-extension.md
  • .agents/references/typeorm.md
  • .github/workflows/release.yml
  • .release-please-manifest.json
  • LICENSE
  • nx.json
  • package.json
  • packages/codec-url-expression/LICENSE
  • packages/codec-url-expression/package.json
  • packages/codec-url-expression/src/decoder/module.ts
  • packages/codec-url-expression/src/encoder/module.ts
  • packages/codec-url-expression/test/unit/encoder-schema.spec.ts
  • packages/codec-url-simple/LICENSE
  • packages/codec-url-simple/package.json
  • packages/codec-url-simple/src/decoder/module.ts
  • packages/codec-url-simple/src/encoder/module.ts
  • packages/codec-url-simple/test/unit/decoder.spec.ts
  • packages/codec-url-simple/test/unit/encoder-schema.spec.ts
  • packages/codec-url/LICENSE
  • packages/codec-url/package.json
  • packages/codec-url/src/module.ts
  • packages/codec-url/src/types.ts
  • packages/codec-url/test/unit/registry.spec.ts
  • packages/core/LICENSE
  • packages/core/package.json
  • packages/core/src/errors/code.ts
  • packages/core/src/errors/schema.ts
  • packages/core/src/parameter/filters/record/types.ts
  • packages/core/src/parser/base.ts
  • packages/core/src/parser/parameter/filters/index.ts
  • packages/core/src/parser/parameter/filters/validate.ts
  • packages/core/src/parser/query.ts
  • packages/core/src/parser/types.ts
  • packages/core/test/unit/parameter/filters-validation.spec.ts
  • packages/docs/guide/errors.md
  • packages/docs/guide/executing-queries.md
  • packages/docs/guide/filters.md
  • packages/docs/guide/migration-typeorm-extension.md
  • packages/docs/package.json
  • packages/docs/packages/codec-url-expression.md
  • packages/docs/packages/codec-url-simple.md
  • packages/docs/packages/codec-url.md
  • packages/docs/packages/parser-expression.md
  • packages/docs/packages/parser-mongo.md
  • packages/docs/packages/parser-simple.md
  • packages/docs/packages/sql.md
  • packages/docs/packages/typeorm.md
  • packages/memory/LICENSE
  • packages/memory/package.json
  • packages/memory/src/parameter/filters/compiler.ts
  • packages/parser-expression/LICENSE
  • packages/parser-expression/package.json
  • packages/parser-expression/src/parameter/filters/constants.ts
  • packages/parser-expression/src/parameter/filters/module.ts
  • packages/parser-expression/test/unit/parser/filters.spec.ts
  • packages/parser-mongo/LICENSE
  • packages/parser-mongo/package.json
  • packages/parser-mongo/src/parameter/filters/module.ts
  • packages/parser-mongo/test/unit/parser/filters.spec.ts
  • packages/parser-simple/LICENSE
  • packages/parser-simple/package.json
  • packages/parser-simple/src/parameter/fields/module.ts
  • packages/parser-simple/src/parameter/filters/module.ts
  • packages/parser-simple/src/parameter/pagination/module.ts
  • packages/parser-simple/src/parameter/relations/module.ts
  • packages/parser-simple/src/parameter/sorts/module.ts
  • packages/parser-simple/test/unit/parser/filters.spec.ts
  • packages/parser-simple/test/unit/parser/parser.spec.ts
  • packages/sql/LICENSE
  • packages/sql/package.json
  • packages/sql/src/adapter/module.ts
  • packages/sql/src/adapter/relations/base.ts
  • packages/sql/src/adapter/relations/types.ts
  • packages/sql/src/dialect/oracle.ts
  • packages/sql/src/dialect/pg.ts
  • packages/sql/src/helpers/relation-alias.ts
  • packages/sql/src/visitor/filters.ts
  • packages/sql/test/unit/adapter.spec.ts
  • packages/sql/test/unit/interpreters/elem-match.spec.ts
  • packages/sql/test/unit/interpreters/regex.spec.ts
  • packages/sql/test/unit/interpreters/relation-nested.spec.ts
  • packages/sql/test/unit/interpreters/relation.spec.ts
  • packages/typeorm/LICENSE
  • packages/typeorm/package.json
  • packages/typeorm/src/adapter/filters.ts
  • packages/typeorm/test/unit/acceptance.spec.ts
  • packages/typeorm/test/unit/adapter/module.spec.ts
  • packages/typeorm/test/unit/adapter/relations.spec.ts
  • release-please-config.json

Comment thread packages/sql/src/visitor/filters.ts Outdated
Comment on lines +86 to +88
const sql = queryBuilder.getSql();
expect(sql).toContain('WHERE "user"."id" = 1 AND');
expect(sql).toContain('"user"."age" = 18');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the TypeORM SQL string assertions to expect parameter placeholders.

TypeORM's getSql() method does not inline literal parameter values (like 1 or 18) into the generated SQL string. Instead, it uses parameter placeholders (such as ?, $1, or :actorId) depending on the active driver. You should use getQueryAndParameters() to robustly assert both the SQL structure and the parameter values.

  • packages/typeorm/test/unit/adapter/module.spec.ts#L86-L88: extract the SQL and parameters via getQueryAndParameters() and match against standard placeholders (e.g., WHERE "user"."id" = ? AND "user"."age" = ?) while verifying params contains 1 and 18.
  • packages/typeorm/test/unit/adapter/module.spec.ts#L101-L101: extract via getQueryAndParameters() and match against the placeholder for "user"."id" while verifying params contains 1.
🐛 Proposed fixes

For lines 86-88:

-        const sql = queryBuilder.getSql();
-        expect(sql).toContain('WHERE "user"."id" = 1 AND');
-        expect(sql).toContain('"user"."age" = 18');
+        const [sql, params] = queryBuilder.getQueryAndParameters();
+        expect(sql).toMatch(/WHERE "user"\."id" = (?:\?|\$1|:actorId) AND/);
+        expect(sql).toMatch(/"user"\."age" = (?:\?|\$2|:[a-zA-Z0-9_]+)/);
+        expect(params).toEqual(expect.arrayContaining([1, 18]));

For line 101:

-        expect(queryBuilder.getSql()).toContain('WHERE "user"."id" = 1');
+        const [sql, params] = queryBuilder.getQueryAndParameters();
+        expect(sql).toMatch(/WHERE "user"\."id" = (?:\?|\$1|:actorId)/);
+        expect(params).toEqual(expect.arrayContaining([1]));
📍 Affects 1 file
  • packages/typeorm/test/unit/adapter/module.spec.ts#L86-L88 (this comment)
  • packages/typeorm/test/unit/adapter/module.spec.ts#L101-L101
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/typeorm/test/unit/adapter/module.spec.ts` around lines 86 - 88,
Update the SQL assertions in packages/typeorm/test/unit/adapter/module.spec.ts
at lines 86-88 and 101 to use queryBuilder.getQueryAndParameters(). At lines
86-88, assert the generated SQL uses parameter placeholders for both user.id and
user.age, and verify the returned parameters contain 1 and 18; at line 101,
assert the user.id placeholder and verify the parameters contain 1.

@tada5hi

tada5hi commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

@coderabbitai pause

@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
✅ Action performed

Reviews paused.

Pass string patterns through without parsing them with JavaScript so each database engine can apply its own regex syntax.
@tada5hi
tada5hi merged commit 51a906a into master Jul 15, 2026
7 checks passed
@github-actions github-actions Bot mentioned this pull request Jul 15, 2026
@github-actions github-actions Bot mentioned this pull request Jul 19, 2026
@tada5hi
tada5hi deleted the fix/v2-beta-release-hardening branch July 27, 2026 07:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants