Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds record-style (named) argument support for aggregation operators and accumulators: new Changes
Sequence DiagramsequenceDiagram
participant User as User
participant QB as QueryBuilder
participant AST as AggregationAST
participant Adapter as MongoAdapter
participant Output as BSON
User->>QB: call fn.dateToString({ date, format })
QB->>AST: MongoAggOperator.of('$dateToString', { date, format })
AST->>AST: shallow-copy & freeze record args
AST-->>QB: Operator node (record args)
User->>QB: call acc.topN({ output, sortBy, n })
QB->>AST: MongoAggAccumulator.of('$topN', { output, sortBy, n })
AST->>AST: shallow-copy & freeze record arg
AST-->>QB: Accumulator node (record arg)
QB->>Adapter: lower aggregation expression tree
Adapter->>Adapter: isRecordArgs? → lowerExprRecord recursively
Adapter-->>Output: { $dateToString: { date: ..., format: ... } }
Adapter-->>Output: { $topN: { output: ..., sortBy: ..., n: ... } }
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
@prisma-next/mongo-runtime
@prisma-next/family-mongo
@prisma-next/sql-runtime
@prisma-next/family-sql
@prisma-next/extension-paradedb
@prisma-next/extension-pgvector
@prisma-next/postgres
@prisma-next/sql-orm-client
@prisma-next/target-mongo
@prisma-next/adapter-mongo
@prisma-next/driver-mongo
@prisma-next/contract
@prisma-next/utils
@prisma-next/config
@prisma-next/errors
@prisma-next/framework-components
@prisma-next/operations
@prisma-next/contract-authoring
@prisma-next/ids
@prisma-next/psl-parser
@prisma-next/psl-printer
@prisma-next/cli
@prisma-next/emitter
@prisma-next/migration-tools
@prisma-next/vite-plugin-contract-emit
@prisma-next/runtime-executor
@prisma-next/mongo-codec
@prisma-next/mongo-contract
@prisma-next/mongo-value
@prisma-next/mongo-contract-psl
@prisma-next/mongo-emitter
@prisma-next/mongo-query-ast
@prisma-next/mongo-orm
@prisma-next/mongo-pipeline-builder
@prisma-next/mongo-lowering
@prisma-next/mongo-wire
@prisma-next/sql-contract
@prisma-next/sql-errors
@prisma-next/sql-operations
@prisma-next/sql-schema-ir
@prisma-next/sql-contract-psl
@prisma-next/sql-contract-ts
@prisma-next/sql-contract-emitter
@prisma-next/sql-lane-query-builder
@prisma-next/sql-relational-core
@prisma-next/sql-builder
@prisma-next/target-postgres
@prisma-next/adapter-postgres
@prisma-next/driver-postgres
commit: |
4ee3b42 to
b7f80c8
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
packages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test.ts (1)
106-112: Validate positional helper arity explicitly.On Line 106-Line 112, casting to variadic and always passing three args can let arity bugs slip through. Add expected arg count per helper and assert
op.args.length.As per coding guidelines, tests must verify behavior rather than loosely mirroring fixture invocation patterns.♻️ Proposed arity-aware test shape
- it.each([ - ['add', '$add'], + it.each([ + ['add', '$add', 3], ['subtract', '$subtract'], ['multiply', '$multiply'], ... - ] as const)('fn.%s produces operator %s with array args', (helperName, expectedOp) => { + ] as const)('fn.%s produces operator %s with array args', (helperName, expectedOp, argCount) => { const helper = fn[helperName] as (...a: TypedAggExpr<DocField>[]) => TypedAggExpr<DocField>; const result = helper(d, d, d); expect(result.node).toBeInstanceOf(MongoAggOperator); const op = result.node as MongoAggOperator; expect(op.op).toBe(expectedOp); expect(Array.isArray(op.args)).toBe(true); + expect((op.args as ReadonlyArray<unknown>).length).toBe(argCount); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test.ts` around lines 106 - 112, The test currently invokes helpers via const helper = fn[helperName] as (...a: TypedAggExpr<DocField>[]) => TypedAggExpr<DocField> and always calls helper(d, d, d), which hides arity bugs; add an expected-arity lookup (e.g., a map from helperName to expectedArgCount) and assert op.args.length === expectedArgCount after creating result (using result.node and op as in the diff). Update the invocation to pass exactly expectedArgCount arguments (or build an args array of length expectedArgCount) and keep the existing assertions that op is a MongoAggOperator and op.args is an array.packages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test.ts (1)
46-50: Tighten record-arg key assertions to exact-match.On Line 48-Line 50, the test verifies expected keys exist, but it won’t fail if unexpected keys are added. Assert exact key sets to catch arg-shape regressions.
♻️ Proposed test assertion refinement
- const recordArg = result.node.arg as Readonly<Record<string, unknown>>; - for (const key of Object.keys(args)) { - expect(recordArg).toHaveProperty(key); - } + const recordArg = result.node.arg as Readonly<Record<string, unknown>>; + expect(Object.keys(recordArg).sort()).toEqual(Object.keys(args).sort());🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test.ts` around lines 46 - 50, The test currently checks only that each expected key exists on result.node.arg (via isRecordArgs and a loop), which won't catch extra unexpected keys; change the assertion to assert exact key sets instead: after casting result.node.arg to Readonly<Record<string, unknown>> (as done now), compare the set/array of Object.keys(recordArg) to Object.keys(args) for exact equality (sort both arrays or compare as sets) so the test fails if extra or missing keys are present; keep the existing isRecordArgs check and use the identifiers result.node.arg, recordArg, and args to locate and update the assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@packages/2-mongo-family/5-query-builders/pipeline-builder/src/expression-helpers.ts`:
- Around line 408-414: The zip() helper currently types its args.inputs as a
single TypedAggExpr<ArrayField>, but MongoDB requires inputs to be an array of
array expressions; update the zip signature so args.inputs is
TypedAggExpr<ArrayField>[] (matching variadic helpers like setUnion()), adjust
any related type references in the zip declaration and keep returning
namedArgsExpr('$zip', args, ARRAY) so the emitted { $zip: { inputs: [ ... ] } }
structure is produced.
---
Nitpick comments:
In
`@packages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test.ts`:
- Around line 46-50: The test currently checks only that each expected key
exists on result.node.arg (via isRecordArgs and a loop), which won't catch extra
unexpected keys; change the assertion to assert exact key sets instead: after
casting result.node.arg to Readonly<Record<string, unknown>> (as done now),
compare the set/array of Object.keys(recordArg) to Object.keys(args) for exact
equality (sort both arrays or compare as sets) so the test fails if extra or
missing keys are present; keep the existing isRecordArgs check and use the
identifiers result.node.arg, recordArg, and args to locate and update the
assertion.
In
`@packages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test.ts`:
- Around line 106-112: The test currently invokes helpers via const helper =
fn[helperName] as (...a: TypedAggExpr<DocField>[]) => TypedAggExpr<DocField> and
always calls helper(d, d, d), which hides arity bugs; add an expected-arity
lookup (e.g., a map from helperName to expectedArgCount) and assert
op.args.length === expectedArgCount after creating result (using result.node and
op as in the diff). Update the invocation to pass exactly expectedArgCount
arguments (or build an args array of length expectedArgCount) and keep the
existing assertions that op is a MongoAggOperator and op.args is an array.
🪄 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: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 8e5a51d5-4bf9-47d3-bceb-1d53c1355391
⛔ Files ignored due to path filters (3)
projects/mongo-pipeline-builder/plans/expression-accumulator-helpers-plan.mdis excluded by!projects/**projects/mongo-pipeline-builder/specs/expression-accumulator-helpers.spec.mdis excluded by!projects/**projects/mongo-pipeline-builder/specs/reviews/code-review.mdis excluded by!projects/**
📒 Files selected for processing (19)
packages/2-mongo-family/4-query/query-ast/src/aggregation-expressions.tspackages/2-mongo-family/4-query/query-ast/src/exports/index.tspackages/2-mongo-family/4-query/query-ast/test/aggregation-expressions.test-d.tspackages/2-mongo-family/4-query/query-ast/test/aggregation-expressions.test.tspackages/2-mongo-family/5-query-builders/pipeline-builder/DEVELOPING.mdpackages/2-mongo-family/5-query-builders/pipeline-builder/README.mdpackages/2-mongo-family/5-query-builders/pipeline-builder/src/accumulator-helpers.tspackages/2-mongo-family/5-query-builders/pipeline-builder/src/exports/index.tspackages/2-mongo-family/5-query-builders/pipeline-builder/src/expression-helpers.tspackages/2-mongo-family/5-query-builders/pipeline-builder/src/types.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test-d.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test-d.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/fixtures/test-contract.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/types.test-d.tspackages/3-mongo-target/2-mongo-adapter/src/lowering.tspackages/3-mongo-target/2-mongo-adapter/test/lowering.test.tstest/integration/test/mongo/pipeline-builder.test.ts
packages/2-mongo-family/5-query-builders/pipeline-builder/src/expression-helpers.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
packages/2-mongo-family/4-query/query-ast/src/aggregation-expressions.ts (1)
4-24:⚠️ Potential issue | 🟠 MajorWiden
AggRecordArgsbeyond scalar values.
AggRecordArgsonly permitsMongoAggExprvalues, so the new named-arg path cannot represent operators that need array-valued slots. The downstream$ziphelper is already forced into{ inputs: <expr> }/{ defaults: <expr> }, andrewriteRecordArgs()bakes the same scalar assumption into traversal. Please widen the record-arg value type and recurse over nested arrays before shipping the “full operator set”.MongoDB aggregation `$zip` operator syntax: what types are required for the `inputs` and `defaults` fields?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/2-mongo-family/4-query/query-ast/src/aggregation-expressions.ts` around lines 4 - 24, AggRecordArgs is too narrow (values typed only as MongoAggExpr) so named-arg operators that accept arrays or nested records (e.g., $zip.inputs/defaults) cannot be represented or rewritten; change AggRecordArgs to allow nested arrays and records (e.g., value type = MongoAggExpr | ReadonlyArray<MongoAggExpr> | AggRecordArgs) and update isRecordArgs and rewriteRecordArgs to handle those cases by recursing: when a value is an array, map/rewrite each element; when a value is a record, call rewriteRecordArgs recursively; keep the same readonly/Record<string, ...> shapes and ensure rewriteRecordArgs returns AggRecordArgs with rewritten nested arrays and records using the MongoAggExpr.rewrite(rewriter) for scalar leaves.
🧹 Nitpick comments (1)
packages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test.ts (1)
115-149: Lock the$zipshape down with a dedicated case.The named-args table only checks that each key exists. A helper-specific zip assertion that inspects
inputs/defaultswould catch the array-valued path that the generic smoke test currently misses.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test.ts` around lines 115 - 149, The generic named-args test for fn['zip']/$zip only verifies key presence and misses validating the array shape of the inputs/defaults; add a dedicated case for the 'zip' helper that calls the zip helper (fn['zip']) with a typed record and then asserts op.args.inputs is an array (and if present op.args.defaults is an array or undefined) and that each element of inputs is the expected TypedAggExpr/element shape; reuse the existing result.node -> MongoAggOperator extraction (as in the test) and isRecordArgs check before inspecting recordArgs.inputs and recordArgs.defaults to ensure the helper produces the correct array-valued structure.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@packages/2-mongo-family/5-query-builders/pipeline-builder/src/accumulator-helpers.ts`:
- Around line 117-155: The top/bottom/topN/bottomN accumulator helpers accept
sortBy as TypedAggExpr<DocField> but must require a sort-spec document; update
their args so sortBy is a dedicated sort-spec type (e.g., SortSpec or
TypedSortSpec) and inside each helper wrap the provided sort spec with
MongoAggLiteral.of(...) before passing to namedAccumulatorArgs(args) so the
emitted accumulator uses a literal sort document; adjust types on top, bottom,
topN and bottomN and ensure namedAccumulatorArgs is called with the wrapped sort
value.
In
`@packages/2-mongo-family/5-query-builders/pipeline-builder/src/expression-helpers.ts`:
- Around line 93-107: The current helpers docUnaryExpr and nullableDocUnaryExpr
incorrectly propagate the input arg._field.codecId into the returned _field,
which breaks shape-changing operators (e.g., arrayElemAt, firstElem, lastElem,
$arrayToObject) by leaving an array codec on an element/object result; update
call sites that use docUnaryExpr/nullableDocUnaryExpr (and the other similar
helpers) to provide an explicit output field descriptor instead of copying
arg._field.codecId so the returned TypedAggExpr has the correct codecId and
nullability for the transformed shape; search for usages like arrayElemAt,
firstElem, lastElem and arrayToObject and replace the helper calls with ones
that construct the proper {_field: { codecId: <correctCodecId>, nullable:
<true|false> }, node: MongoAggOperator.of(...)} or add an overload/variant that
accepts an explicit output descriptor to avoid copying the input codec.
---
Duplicate comments:
In `@packages/2-mongo-family/4-query/query-ast/src/aggregation-expressions.ts`:
- Around line 4-24: AggRecordArgs is too narrow (values typed only as
MongoAggExpr) so named-arg operators that accept arrays or nested records (e.g.,
$zip.inputs/defaults) cannot be represented or rewritten; change AggRecordArgs
to allow nested arrays and records (e.g., value type = MongoAggExpr |
ReadonlyArray<MongoAggExpr> | AggRecordArgs) and update isRecordArgs and
rewriteRecordArgs to handle those cases by recursing: when a value is an array,
map/rewrite each element; when a value is a record, call rewriteRecordArgs
recursively; keep the same readonly/Record<string, ...> shapes and ensure
rewriteRecordArgs returns AggRecordArgs with rewritten nested arrays and records
using the MongoAggExpr.rewrite(rewriter) for scalar leaves.
---
Nitpick comments:
In
`@packages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test.ts`:
- Around line 115-149: The generic named-args test for fn['zip']/$zip only
verifies key presence and misses validating the array shape of the
inputs/defaults; add a dedicated case for the 'zip' helper that calls the zip
helper (fn['zip']) with a typed record and then asserts op.args.inputs is an
array (and if present op.args.defaults is an array or undefined) and that each
element of inputs is the expected TypedAggExpr/element shape; reuse the existing
result.node -> MongoAggOperator extraction (as in the test) and isRecordArgs
check before inspecting recordArgs.inputs and recordArgs.defaults to ensure the
helper produces the correct array-valued structure.
🪄 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: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: ef22ab17-84c3-4e4e-87f7-72addcfbd721
⛔ Files ignored due to path filters (4)
projects/mongo-pipeline-builder/plan.mdis excluded by!projects/**projects/mongo-pipeline-builder/plans/expression-accumulator-helpers-plan.mdis excluded by!projects/**projects/mongo-pipeline-builder/specs/expression-accumulator-helpers.spec.mdis excluded by!projects/**projects/mongo-pipeline-builder/specs/reviews/code-review.mdis excluded by!projects/**
📒 Files selected for processing (19)
packages/2-mongo-family/4-query/query-ast/src/aggregation-expressions.tspackages/2-mongo-family/4-query/query-ast/src/exports/index.tspackages/2-mongo-family/4-query/query-ast/test/aggregation-expressions.test-d.tspackages/2-mongo-family/4-query/query-ast/test/aggregation-expressions.test.tspackages/2-mongo-family/5-query-builders/pipeline-builder/DEVELOPING.mdpackages/2-mongo-family/5-query-builders/pipeline-builder/README.mdpackages/2-mongo-family/5-query-builders/pipeline-builder/src/accumulator-helpers.tspackages/2-mongo-family/5-query-builders/pipeline-builder/src/exports/index.tspackages/2-mongo-family/5-query-builders/pipeline-builder/src/expression-helpers.tspackages/2-mongo-family/5-query-builders/pipeline-builder/src/types.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test-d.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test-d.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/fixtures/test-contract.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/types.test-d.tspackages/3-mongo-target/2-mongo-adapter/src/lowering.tspackages/3-mongo-target/2-mongo-adapter/test/lowering.test.tstest/integration/test/mongo/pipeline-builder.test.ts
✅ Files skipped from review due to trivial changes (8)
- packages/2-mongo-family/5-query-builders/pipeline-builder/src/exports/index.ts
- packages/2-mongo-family/5-query-builders/pipeline-builder/test/types.test-d.ts
- packages/3-mongo-target/2-mongo-adapter/test/lowering.test.ts
- packages/2-mongo-family/5-query-builders/pipeline-builder/src/types.ts
- packages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test-d.ts
- packages/2-mongo-family/5-query-builders/pipeline-builder/README.md
- packages/2-mongo-family/5-query-builders/pipeline-builder/DEVELOPING.md
- packages/2-mongo-family/4-query/query-ast/test/aggregation-expressions.test.ts
🚧 Files skipped from review as they are similar to previous changes (6)
- packages/2-mongo-family/5-query-builders/pipeline-builder/test/fixtures/test-contract.ts
- packages/2-mongo-family/4-query/query-ast/src/exports/index.ts
- packages/2-mongo-family/4-query/query-ast/test/aggregation-expressions.test-d.ts
- packages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test.ts
- packages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test-d.ts
- test/integration/test/mongo/pipeline-builder.test.ts
packages/2-mongo-family/5-query-builders/pipeline-builder/src/accumulator-helpers.ts
Show resolved
Hide resolved
packages/2-mongo-family/5-query-builders/pipeline-builder/src/expression-helpers.ts
Show resolved
Hide resolved
There was a problem hiding this comment.
♻️ Duplicate comments (1)
packages/2-mongo-family/5-query-builders/pipeline-builder/src/accumulator-helpers.ts (1)
117-156:⚠️ Potential issue | 🟠 Major
sortByis typed too broadly for top/bottom accumulators (Mongo contract mismatch).At Line 119, Line 129, Line 139, and Line 150,
sortBycurrently acceptsTypedAggExpr<DocField>, which permits invalid inputs like computed expressions. MongoDB expects a literal sort-spec document for$top/$bottom/$topN/$bottomN({ field: 1 | -1, ... }). This should be modeled as a sort-spec input and lowered viaMongoAggLiteral.of(sortSpec).Proposed fix
import type { MongoAggExpr } from '@prisma-next/mongo-query-ast'; -import { MongoAggAccumulator } from '@prisma-next/mongo-query-ast'; +import { MongoAggAccumulator, MongoAggLiteral } from '@prisma-next/mongo-query-ast'; @@ +type SortSpec = Readonly<Record<string, 1 | -1>>; @@ - top(args: { - output: TypedAggExpr<DocField>; - sortBy: TypedAggExpr<DocField>; - }): TypedAccumulatorExpr<DocField> { + top<F extends DocField>(args: { + output: TypedAggExpr<F>; + sortBy: SortSpec; + }): TypedAccumulatorExpr<F> { return { _field: undefined as never, - node: MongoAggAccumulator.of('$top', namedAccumulatorArgs(args)), + node: MongoAggAccumulator.of('$top', { + output: args.output.node, + sortBy: MongoAggLiteral.of(args.sortBy), + }), }; }, @@ - bottom(args: { - output: TypedAggExpr<DocField>; - sortBy: TypedAggExpr<DocField>; - }): TypedAccumulatorExpr<DocField> { + bottom<F extends DocField>(args: { + output: TypedAggExpr<F>; + sortBy: SortSpec; + }): TypedAccumulatorExpr<F> { return { _field: undefined as never, - node: MongoAggAccumulator.of('$bottom', namedAccumulatorArgs(args)), + node: MongoAggAccumulator.of('$bottom', { + output: args.output.node, + sortBy: MongoAggLiteral.of(args.sortBy), + }), }; }, @@ - topN(args: { - output: TypedAggExpr<DocField>; - sortBy: TypedAggExpr<DocField>; + topN(args: { + output: TypedAggExpr<DocField>; + sortBy: SortSpec; n: TypedAggExpr<NumericField>; }): TypedAccumulatorExpr<ArrayField> { return { _field: undefined as never, - node: MongoAggAccumulator.of('$topN', namedAccumulatorArgs(args)), + node: MongoAggAccumulator.of('$topN', { + output: args.output.node, + sortBy: MongoAggLiteral.of(args.sortBy), + n: args.n.node, + }), }; }, @@ - bottomN(args: { - output: TypedAggExpr<DocField>; - sortBy: TypedAggExpr<DocField>; + bottomN(args: { + output: TypedAggExpr<DocField>; + sortBy: SortSpec; n: TypedAggExpr<NumericField>; }): TypedAccumulatorExpr<ArrayField> { return { _field: undefined as never, - node: MongoAggAccumulator.of('$bottomN', namedAccumulatorArgs(args)), + node: MongoAggAccumulator.of('$bottomN', { + output: args.output.node, + sortBy: MongoAggLiteral.of(args.sortBy), + n: args.n.node, + }), }; },MongoDB docs: for aggregation accumulators $top, $bottom, $topN, and $bottomN, what is the required type/shape of the sortBy argument?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/2-mongo-family/5-query-builders/pipeline-builder/src/accumulator-helpers.ts` around lines 117 - 156, The top/bottom/topN/bottomN accumulators accept a too-broad TypedAggExpr<DocField> for the sortBy argument; change the sortBy param type to a literal sort-spec type (a document mapping field names to 1 | -1) and ensure you wrap the provided sort-spec with MongoAggLiteral.of(...) before passing into MongoAggAccumulator.of inside namedAccumulatorArgs; update the signatures in top, bottom, topN, and bottomN and the call sites so sortSpec is modeled and lowered as a literal per MongoDB's required sort-spec shape.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In
`@packages/2-mongo-family/5-query-builders/pipeline-builder/src/accumulator-helpers.ts`:
- Around line 117-156: The top/bottom/topN/bottomN accumulators accept a
too-broad TypedAggExpr<DocField> for the sortBy argument; change the sortBy
param type to a literal sort-spec type (a document mapping field names to 1 |
-1) and ensure you wrap the provided sort-spec with MongoAggLiteral.of(...)
before passing into MongoAggAccumulator.of inside namedAccumulatorArgs; update
the signatures in top, bottom, topN, and bottomN and the call sites so sortSpec
is modeled and lowered as a literal per MongoDB's required sort-spec shape.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: be4be4e5-9f68-4f9d-9ea8-9bedd476a883
⛔ Files ignored due to path filters (1)
projects/mongo-pipeline-builder/specs/reviews/code-review.mdis excluded by!projects/**
📒 Files selected for processing (6)
packages/2-mongo-family/5-query-builders/pipeline-builder/src/accumulator-helpers.tspackages/2-mongo-family/5-query-builders/pipeline-builder/src/exports/index.tspackages/2-mongo-family/5-query-builders/pipeline-builder/src/expression-helpers.tspackages/2-mongo-family/5-query-builders/pipeline-builder/src/types.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test-d.tspackages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test-d.ts
✅ Files skipped from review due to trivial changes (1)
- packages/2-mongo-family/5-query-builders/pipeline-builder/src/exports/index.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- packages/2-mongo-family/5-query-builders/pipeline-builder/test/accumulator-helpers.test-d.ts
- packages/2-mongo-family/5-query-builders/pipeline-builder/src/types.ts
- packages/2-mongo-family/5-query-builders/pipeline-builder/test/expression-helpers.test-d.ts
- packages/2-mongo-family/5-query-builders/pipeline-builder/src/expression-helpers.ts
dec26d4 to
f15fd4e
Compare
Task spec and execution plan for completing the typed expression and accumulator helpers in the pipeline builder. Key design decision: extend MongoAggOperator and MongoAggAccumulator to support named arguments natively rather than working around the limitation.
…goAggAccumulator
Widen MongoAggOperator.args and MongoAggAccumulator.arg to accept
Readonly<Record<string, MongoAggExpr>> alongside existing forms.
Update rewrite() to recurse into record entries and lowering to
produce { [op]: { key: lowered } } for the record form.
This unblocks all named-args expression and accumulator helpers
(e.g. $dateToString, $topN).
Add BooleanField (mongo/bool@1) and DateField (mongo/date@1) types to the pipeline builder and export them from the package. Add codec entries to test fixtures and type tests verifying ResolveRow.
Add ~65 typed expression helpers covering date (13), string (13), comparison (7), array (11), set (7), type (10), and object (4) operators. Named-arg operators use the record-form MongoAggOperator. Each helper is verified by a type test for its TypedAggExpr<F> return type.
Add stdDevPop/stdDevSamp (NullableNumericField), firstN/lastN/maxN/minN (named args, ArrayField), and top/bottom/topN/bottomN (named args, DocField/ArrayField) to the acc object. Includes static factory methods on MongoAggAccumulator and type tests for every new helper.
Document all expression and accumulator helpers in README.md with categorized tables. Add named-argument pattern and field type alias reference to DEVELOPING.md.
All milestones and acceptance criteria met.
…m lowering The type guards isExprArray and isRecordArgs were duplicated between query-ast and adapter-mongo with identical logic. Export them (and the AggRecordArgs type alias) from query-ast public API so downstream consumers can import rather than copy.
Parameterized tests verify that each helper produces the correct MongoDB operator string and argument shape (unary, positional array, or named-args record). Covers all 65 expression helpers and 10 new accumulator helpers.
Extend the pipeline-builder integration test with a createdAt date field and 4 representative tests covering the novel patterns: - fn.dateToString (named-args date expression) - fn.trim (named-args string expression) - fn.gt in $cond (positional boolean expression) - acc.firstN (named-args accumulator)
$first, $last (array forms), and $arrayElemAt can return null when the array is empty or the index is out of bounds. Add NullableDocField type alias and use it as the return type for these three helpers.
Replace Record<string, TypedAggExpr<DocField>> with per-helper record types that enforce correct keys and per-key field types (DateField, StringField, NumericField, etc.). This catches typos, missing required keys, and wrong value types at compile time.
Replace Record<string, TypedAggExpr<DocField>> with per-helper record types enforcing correct keys and value types (e.g. n requires NumericField). Consistent with the expression helper narrowing.
Use properly typed fixtures (s for StringField, dt for DateField, n for NumericField, etc.) in named-args helper call sites. Add negative type tests verifying that wrong-type arguments are rejected at compile time.
Introduce typed fixtures (s for StringField, n for NumericField, dt for DateField, arr for ArrayField) in the named-args test tables so runtime tests pass with the narrowed helper signatures.
All five code review findings (F01-F05) are now resolved. The deferred items section is removed as no items remain deferred.
… deferred These were listed as "deferred" but TML-2217 is the final task in the project — there is nothing to defer to. Reclassify them as known gaps in the spec, code review, and parent plan.
Add LiteralValue<F> conditional type that maps known field types to their JS value types (StringField->string, NumericField->number, etc.). Use overloads for direct inference from value type, plus a generic overload with LiteralValue<F> for contextual inference. Unknown codec IDs fall through to unknown (escape hatch for custom codecs).
$sum returns the same numeric type as its input (unlike $avg/$stdDev which always return doubles). Making the signature generic preserves integer/decimal codecs through the type system.
All originally-identified known gaps are now addressed. Update task spec, parent spec, parent plan, and task plan to reflect that fn.literal type safety and acc.sum codec preservation are resolved. Mark TML-2217 as complete in parent spec status table.
Add fallback branch that checks for codecId directly on the field object, not only under type.kind.scalar. This fixes integration test contracts that use simplified field shapes (MongoContract intersection) where the ContractFieldType union prevents the scalar branch from matching.
5f6f1d9 to
93afc7c
Compare
closes TML-2217
Key snippet (new capability)
Intent
Expand the pipeline builder's
fn(expression) andacc(accumulator) helpers from a starter set (~10 each) to the full MongoDB aggregation operator set (~65 expression helpers, ~10 new accumulators). This requires extending the AST to support named-argument operators natively, since many MongoDB operators (date, string, regex, top/bottom accumulators) take{ key: expr }records rather than positional arrays.Change map
BooleanField,DateField,NullableDocFieldThe story
Extend the AST to support named-argument operators.
MongoAggOperator.argsandMongoAggAccumulator.argare widened to acceptReadonly<Record<string, MongoAggExpr>>alongside existing forms. Constructors freeze record args for immutability.rewrite()recurses into record entries. Type guards (isExprArray,isRecordArgs) are exported from query-ast and reused by the lowering module (eliminating prior duplication).Add internal factory functions for each return-type category.
expression-helpers.tsgainsnumericUnaryExpr,booleanExpr,booleanUnaryExpr,dateUnaryExpr,arrayExpr,arrayUnaryExpr,docUnaryExpr,nullableDocUnaryExpr, andnamedArgsExpr— reducing ~65 helpers to one-liner delegations.Add ~65 expression helpers across 7 categories. Date (13), string (13), comparison (7), array (11), set (7), type (10), and object (4) operators, all on the flat
fnnamespace. Named-args operators likedateToString,trim,regexMatchaccept typed records; positional operators accept typed varargs.Add ~10 accumulator helpers.
stdDevPop,stdDevSamp(single-arg), plus N-variant (firstN,lastN,maxN,minN) and top/bottom (top,bottom,topN,bottomN) accumulators that use named-arg records.Narrow named-args signatures for input type safety. All ~20 named-args helpers use specific record types with per-key field type constraints (e.g.
date: TypedAggExpr<DateField>,n: TypedAggExpr<NumericField>), rejecting wrong types at compile time. Negative type tests verify this.Add nullable precision for array-element accessors.
firstElem,lastElem, andarrayElemAtreturnTypedAggExpr<NullableDocField>instead ofDocField, reflecting that these operators can return null on empty arrays or out-of-bounds indices.Update lowering to handle record args. The adapter lowering visitor branches on
isRecordArgs()to produce{ [op]: { key1: lowered, key2: lowered } }for both operators and accumulators.Behavior changes & evidence
AST accepts named-argument records:
MongoAggOperatorandMongoAggAccumulatornow acceptReadonly<Record<string, MongoAggExpr>>as args, with immutable freezing and full rewrite traversal.$dateToString,$trim,$topNrequire named arguments. Without AST support, these operators could not be represented in the typed pipeline builder.~65 new typed expression helpers on
fn: Adds date, string, comparison, array, set, type, and object operator helpers, each returning the correctTypedAggExpr<F>for its MongoDB output type. Named-args helpers use specific record types with per-key constraints.~10 new typed accumulator helpers on
acc: AddsstdDevPop,stdDevSamp,firstN,lastN,maxN,minN,top,bottom,topN,bottomNwith correct return types and named-arg signatures.firstElem,lastElem,arrayElemAtreturn nullable types: These operators returnTypedAggExpr<NullableDocField>(nullable: true), reflecting that they can return null when the array is empty or the index is out of bounds.nullableDocUnaryExprfactory +arrayElemAtmethodType guards exported and deduplicated:
isExprArrayandisRecordArgsare now exported from@prisma-next/mongo-query-astinstead of being duplicated in the lowering module.New field types:
BooleanField,DateField,NullableDocField: Added totypes.tsand exported from the package index.Compatibility / migration / risk
fn.*andacc.*helpers retain their signatures unchanged.BooleanField,DateField,NullableDocField,NullableNumericField,NumericField,StringField,ArrayField) are additive.arrayElemAt/firstElem/lastElemnullable change: These are new helpers introduced in this branch, so no downstream breakage.Follow-ups / open questions
$sumon int returning int instead of double) is deferred and tracked separately.$accumulator(custom JavaScript accumulator) is out of scope.projects/todocs/and delete the transient project directory once the parent project completes.Non-goals / intentionally out of scope
MongoAggOperatorwith record args suffices.MongoAggArrayFilter,MongoAggMap,MongoAggReduce,MongoAggLet) — they serve a purpose (variable binding semantics) and remain as-is.Summary by CodeRabbit
New Features
Documentation
Tests