Skip to content

fix: Undefined values not stripped in directAccess mode - #10269

Open
yog27ray wants to merge 30 commits into
parse-community:alphafrom
yog27ray:fix/directaccess-undefined-to-null
Open

fix: Undefined values not stripped in directAccess mode#10269
yog27ray wants to merge 30 commits into
parse-community:alphafrom
yog27ray:fix/directaccess-undefined-to-null

Conversation

@yog27ray

@yog27ray yog27ray commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

Issue

When directAccess: true is enabled, ParseServerRESTController bypasses the HTTP layer and routes requests internally. This causes two categories of behavior divergence from the HTTP code path:

1. Undefined values in request body stored as null

undefined values in update (PUT) payloads are converted to null and stored in the database. This breaks doesNotExist / exists queries and changes data semantics.

Root cause: ParseServerRESTController passes request data directly to Parse Server internals without JSON serialization. In HTTP mode, JSON.stringify() naturally strips undefined values from payloads. With directAccess, undefined values are preserved all the way to transformUpdate() in MongoTransform.js, which passes them into MongoDB's $set operator. The MongoDB BSON driver then converts undefined to null.

2. Undefined values in response leak to the client

Cloud function responses containing undefined values (e.g., { questionId: undefined }) are passed directly in-memory to the caller without JSON serialization. In HTTP mode, JSON.stringify naturally strips these undefined properties. With directAccess, the caller receives the raw response object with undefined properties present, causing deep.equal assertions and object key checks to behave differently.

Reproduction (response issue):

// Cloud function that returns undefined values
Parse.Cloud.define('myFunction', () => {
  return {
    definedKey: 'value',
    undefinedKey: undefined,          // should be stripped
    nested: { a: 1, b: undefined },  // b should be stripped
    arrayWithUndefined: [1, undefined, 3],  // undefined → null
  };
});

// With HTTP: { definedKey: 'value', nested: { a: 1 }, arrayWithUndefined: [1, null, 3] }
// With directAccess (before fix): { definedKey: 'value', undefinedKey: undefined, nested: { a: 1, b: undefined }, arrayWithUndefined: [1, undefined, 3] }

Approach

The stripUndefined() helper in ParseServerRESTController.js is now applied to both the request body AND the response:

  1. Request body : body: stripUndefined(data) — strips undefined values before passing to the router, matching HTTP's JSON.stringify behavior on the request path.

  2. Response : stripUndefined(response) — strips undefined values from the response before resolving to the caller, matching HTTP's JSON serialization behavior on the response path.

This ensures directAccess behaves identically to HTTP mode in both directions. The fix is applied at the ParseServerRESTController level — the component added when directAccess is enabled — addressing the root cause at the right layer.

Tasks

  • Add tests
  • Add changes to documentation (guides, repository pages, code comments)
  • Add security check

Summary by CodeRabbit

  • Bug Fixes
    • Undefined values in API responses are now omitted from objects and represented as null in arrays.
    • Undefined values in query parameters are omitted instead of being converted to null.
    • Create and update operations no longer persist undefined fields, including nested fields.

…TTP mode behavior

When `directAccess: true` is enabled, `ParseServerRESTController` passes
request data directly to Parse Server internals without JSON serialization.
In HTTP mode, `JSON.stringify()` naturally strips `undefined` values from
payloads. With directAccess, `undefined` values are preserved, passed to
MongoDB's `$set` operator, and converted to `null` by the BSON driver.

This causes fields that should be absent to be stored as `null`, breaking
`doesNotExist` queries and changing data semantics.

The fix adds a `stripUndefined()` helper that removes keys with `undefined`
values from the request body, making directAccess behave identically to
HTTP mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@parse-github-assistant

Copy link
Copy Markdown

I will reformat the title to use the proper commit message syntax.

@parse-github-assistant parse-github-assistant Bot changed the title fix: strip undefined values in ParseServerRESTController to match HTTP mode fix: Strip undefined values in ParseServerRESTController to match HTTP mode Mar 21, 2026
@parse-github-assistant

parse-github-assistant Bot commented Mar 21, 2026

Copy link
Copy Markdown

🚀 Thanks for opening this pull request! We appreciate your effort in improving the project. Please let us know once your pull request is ready for review.

Tip

  • Keep pull requests small. Large PRs will be rejected. Break complex features into smaller, incremental PRs.
  • Use Test Driven Development. Write failing tests before implementing functionality. Ensure tests pass.
  • Group code into logical blocks. Add a short comment before each block to explain its purpose.
  • We offer conceptual guidance. Coding is up to you. PRs must be merge-ready for human review.
  • Our review focuses on concept, not quality. PRs with code issues will be rejected. Use an AI agent.
  • Human review time is precious. Avoid review ping-pong. Inspect and test your AI-generated code.

Note

Please respond to review comments from AI agents just like you would to comments from a human reviewer. Let the reviewer resolve their own comments, unless they have reviewed and accepted your commit, or agreed with your explanation for why the feedback was incorrect.

Caution

Pull requests must be written using an AI agent with human supervision. Pull requests written entirely by a human will likely be rejected, because of lower code quality, higher review effort and the higher risk of introducing bugs. Please note that AI review comments on this pull request alone do not satisfy this requirement. Our CI and AI review are safeguards, not development tools. If many issues are flagged, rethink your development approach. Invest more effort in planning and design rather than using review cycles to fix low-quality code.

@coderabbitai

coderabbitai Bot commented Mar 21, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

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

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: d7aa9e15-97fd-4d6c-b788-99ce051ec817

📥 Commits

Reviewing files that changed from the base of the PR and between 383d3e5 and b65e383.

📒 Files selected for processing (2)
  • spec/ParseServerRESTController.spec.js
  • src/ParseServerRESTController.js

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

Adds recursive stripUndefined processing for request bodies, query parameters, and responses. Object properties with undefined are omitted. Undefined array elements become null. Tests cover direct-access and HTTP requests, queries, creates, updates, and nested values.

Changes

Undefined value normalization

Layer / File(s) Summary
Controller normalization flow
src/ParseServerRESTController.js
Adds stripUndefined and applies it to request bodies, query parameters, and successful responses.
Normalization test coverage
spec/ParseServerRESTController.spec.js
Adds direct-access and HTTP tests for cloud function responses, query parameters, creates, updates, nested values, and array elements.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to b65e3

This aligns directAccess behavior with HTTP serialization: undefined object properties are omitted and undefined array elements become null. The targeted persistence, query, and response behavior is covered without an active merge-blocking risk.

🚥 Pre-merge checks | ✅ 6 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 2 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The title begins with the required fix: prefix, uses a capitalized first word after the prefix, and accurately describes the directAccess undefined-value issue.
Description check ✅ Passed The description includes the issue, root cause, approach, task status, test coverage, and security check. It omits the template's standard Pull Request notice and the explicit Parse Error codes task, …
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.
Security Check ✅ Passed No security vulnerability is introduced by the reviewed changes. The pull request only changes src/ParseServerRESTController.js and tests; it does not alter dependencies, authentication, authorizati…
Engage In Review Feedback ✅ Passed The contributor engaged with the review feedback and made corresponding changes. Evidence includes a reply and commits adding HTTP parity tests (41223c0 and 2928931), nested and create coverage plus G…
  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@parseplatformorg

parseplatformorg commented Mar 21, 2026

Copy link
Copy Markdown
Contributor

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@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

🧹 Nitpick comments (1)
spec/ParseServerRESTController.spec.js (1)

679-695: Add one nested undefined regression case to close the parity gap.

This test is good for top-level fields. Please add a case like { nested: { absentField: undefined } } to ensure nested updates also match HTTP behavior.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/ParseServerRESTController.spec.js` around lines 679 - 695, Add a
nested-undefined regression case to the existing test "should not convert
undefined values to null on update with directAccess" in
ParseServerRESTController.spec.js: after the current PUT that includes
absentField: undefined, also perform a PUT (or include in the same update) with
a nested object like { nested: { absentField: undefined } } and then GET the
object and assert that getRes.nested is defined, getRes.nested.absentField is
undefined, and that 'absentField' is not an own property of getRes.nested;
update expectations in the test to cover both top-level and nested undefined
behavior so nested updates mirror HTTP behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/ParseServerRESTController.js`:
- Around line 32-43: The stripUndefined function currently only removes
undefined at the top level; update stripUndefined to recursively traverse
objects and arrays so its behavior matches JSON.stringify: for objects (function
stripUndefined) iterate keys and if a value is undefined omit the key, otherwise
set key to stripUndefined(value); for arrays return a new array mapping each
element to stripUndefined(element) but convert undefined elements to null (i.e.,
if element === undefined return null); preserve primitives and null as-is and
avoid mutating the original input. Ensure the function handles nested
objects/arrays and returns a fresh structure.

---

Nitpick comments:
In `@spec/ParseServerRESTController.spec.js`:
- Around line 679-695: Add a nested-undefined regression case to the existing
test "should not convert undefined values to null on update with directAccess"
in ParseServerRESTController.spec.js: after the current PUT that includes
absentField: undefined, also perform a PUT (or include in the same update) with
a nested object like { nested: { absentField: undefined } } and then GET the
object and assert that getRes.nested is defined, getRes.nested.absentField is
undefined, and that 'absentField' is not an own property of getRes.nested;
update expectations in the test to cover both top-level and nested undefined
behavior so nested updates mirror HTTP 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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 40b804d3-ed21-4a29-b323-4dff6e0f2cc2

📥 Commits

Reviewing files that changed from the base of the PR and between e8cc676 and a423f0c.

📒 Files selected for processing (2)
  • spec/ParseServerRESTController.spec.js
  • src/ParseServerRESTController.js

Comment thread src/ParseServerRESTController.js
@codecov

codecov Bot commented Mar 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 93.41%. Comparing base (383d3e5) to head (b65e383).

Additional details and impacted files
@@            Coverage Diff             @@
##            alpha   #10269      +/-   ##
==========================================
- Coverage   93.80%   93.41%   -0.40%     
==========================================
  Files         192      192              
  Lines       16863    16877      +14     
  Branches      252      252              
==========================================
- Hits        15818    15765      -53     
- Misses       1023     1086      +63     
- Partials       22       26       +4     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

JSON.parse(JSON.stringify(data)) perfectly replicates HTTP mode's
serialization roundtrip — stripping undefined at all nesting levels,
not just top-level keys.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 21, 2026
…ingify())

JSON.parse(JSON.stringify()) is expensive. Replace with a recursive
stripUndefined that walks the object tree efficiently — strips undefined
keys from objects at all nesting levels and converts undefined array
elements to null, matching JSON.stringify behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 21, 2026

@mtrezza mtrezza left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you add a test to compare that with behavior when directAccess is false? It should yield the same result.

Adds a companion test that verifies the same behavior without directAccess
(HTTP mode) to confirm both paths yield identical results, as requested
in review.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@yog27ray

yog27ray commented Mar 23, 2026

Copy link
Copy Markdown
Contributor Author

@mtrezza Added a companion test that performs the same create/update/fetch via HTTP (non-directAccess) to confirm both paths yield identical results. The test lets the HTTP layer handle JSON serialization naturally (via encodeBody), so undefined values are stripped by the inherent JSON.stringify in HTTP mode — matching the stripUndefined behavior in directAccess mode.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 23, 2026
Remove explicit JSON.stringify/JSON.parse calls from the HTTP mode test,
letting the request helper's encodeBody handle serialization naturally.
This better demonstrates that HTTP mode inherently strips undefined values.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 23, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Mar 23, 2026
@mtrezza

mtrezza commented Mar 23, 2026

Copy link
Copy Markdown
Member

@coderabbitai Always review the PR title as well. If the commit prefix is fix:, like in this case, then the PR title must describe the bug (broken behavior), not the fix (expected behavior).

@coderabbitai

coderabbitai Bot commented Mar 23, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@mtrezza, understood — thank you for the clarification!

The current title "fix: Strip undefined values in ParseServerRESTController to match HTTP mode" describes the fix. Here's a suggested revision that describes the broken behavior instead:

fix: directAccess update with undefined field values persists them as null in MongoDB

Or alternatively:

fix: Undefined values in directAccess PUT requests stored as null, breaking exists/doesNotExist queries

I'll record this convention for future reviews.


✏️ Learnings added
Learnt from: mtrezza
URL: https://github.com/parse-community/parse-server/pull/10269

Timestamp: 2026-03-23T22:11:01.891Z
Learning: In Parse Server PRs (parse-community/parse-server), when the commit/PR type prefix is `fix:`, the PR title must describe the bug (the broken behavior), not the fix (the expected or corrected behavior). For example, instead of "fix: Strip undefined values in ParseServerRESTController to match HTTP mode" (describes the fix), prefer "fix: directAccess update with undefined field values persists them as null in MongoDB" (describes the broken behavior).

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: mtrezza
Repo: parse-community/parse-server PR: 10237
File: src/Routers/PagesRouter.js:552-573
Timestamp: 2026-03-18T17:53:35.669Z
Learning: In parse-community/parse-server, `src/Routers/PagesRouter.js`: the `encodeURIComponent` call in `composePageParamHeaders` is pre-existing behavior extracted from inline code in `pageResponse` and `redirectResponse`. The potential URIError on malformed Unicode (lone surrogates) when `encodePageParamHeaders` is enabled is a known pre-existing issue, not introduced by the CRLF sanitization refactor. Do not flag it as a new issue in PRs that only refactor or consolidate this call.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:48.786Z
Learning: For Parse Server PRs, always suggest an Angular commit convention PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion on every commit. The format should be: type(scope): description. Common types include feat, fix, perf, refactor, docs, test, chore. The scope should identify the subsystem (e.g., graphql, rest, push, security). The description should be action-oriented and clearly convey the change's impact to developers.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-17T15:02:24.824Z
Learning: For Parse Server PRs, always suggest an Angular-style PR title that would make a meaningful changelog entry for developers. Update the PR title suggestion with every new commit to the PR.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 10161
File: src/Adapters/Storage/Postgres/PostgresStorageAdapter.js:1743-1750
Timestamp: 2026-03-09T21:11:01.966Z
Learning: In `src/Adapters/Storage/Postgres/PostgresStorageAdapter.js` (`updateObjectsByQuery`), the nested sub-key `c` (derived from dot-notation originalUpdate keys) is directly interpolated into SQL string literals in the Object Increment path (`->>'${c}'` and `CONCAT('{"${c}":', ...)`). This is a confirmed SQL injection vulnerability tracked as GHSA-gqpp-xgvh-9h7h and will be fixed in a separate dedicated PR. The maintainer (mtrezza) prefers a simpler fix — either single-quote escaping (`c.replace(/'/g, "''")`) or strict key name validation (e.g., `/^[A-Za-z0-9_]+$/`) — over restructuring with `jsonb_build_object`, to minimize SQL structure changes. Do not suggest `jsonb_build_object` for this fix.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-11-08T13:46:04.940Z
Learning: When reviewing Parse Server PRs that add new features, always check whether the feature is documented in the README.md file, though for new Parse Server options this is optional rather than required.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 10128
File: src/Routers/PagesRouter.js:111-112
Timestamp: 2026-03-07T19:09:01.305Z
Learning: In Parse Server (parse-community/parse-server), the PagesRouter (src/Routers/PagesRouter.js) is mounted behind `express.urlencoded({ extended: false })` (src/ParseServer.ts ~line 333). This means request body values are always flat strings — nested objects in req.body are not possible for this router. The `rawToken && typeof rawToken !== 'string' ? rawToken.toString() : rawToken` guard pattern used consistently across verifyEmail (line ~87), resendVerificationEmail (line ~112), requestResetPassword (line ~154), and resetPassword (line ~183) is therefore safe; the malicious-object scenario (e.g., `{ toString: 'x' }`) is unreachable.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 10149
File: src/Controllers/DatabaseController.js:1865-1873
Timestamp: 2026-03-08T21:51:35.204Z
Learning: In `src/Controllers/DatabaseController.js` (`performInitialization`), the `ensureAuthDataUniqueness` index creation is intentionally non-fatal (warn-only, no rethrow). Unlike username/email uniqueness which has been enforced since Parse Server's inception, authData uniqueness is new. Existing production databases may have duplicate authData entries caused by the race condition this PR fixes, so crashing on startup would be a breaking change. The application-level `ensureUniqueAuthDataId` check in `RestWrite.js` still runs as a fallback, and the warning log gives operators visibility to resolve duplicates manually before the index can be created successfully.

Learnt from: Moumouls
Repo: parse-community/parse-server PR: 10204
File: src/Security/CheckGroups/CheckGroupServerConfig.js:145-147
Timestamp: 2026-03-14T21:39:34.558Z
Learning: In Parse Server's `src/Security/CheckGroups/CheckGroupServerConfig.js`, the "Request complexity limits enabled" security check intentionally uses `return` (not `throw 1`) when `requestComplexity` is `undefined` in PS9. This is by design: `requestComplexity` is opt-in in the current major version and will only become a hard-failing security check (throw 1 when undefined) in PS10. The deprecation DEPPS18 in `src/Deprecator/Deprecations.js` communicates this upcoming default change to operators.

Learnt from: mtrezza
Repo: parse-community/parse-server PR: 0
File: :0-0
Timestamp: 2025-12-02T06:55:53.808Z
Learning: When reviewing Parse Server PRs that add or modify Parse Server options, always verify that changes are properly reflected in three files: src/Options/index.js (where changes originate), src/Options/Definitions.js, and src/Options/docs.js. The correct workflow is: make changes in index.js first, then run `npm run definitions` to automatically replicate the changes to Definitions.js and docs.js.

@yog27ray

yog27ray commented Apr 14, 2026

Copy link
Copy Markdown
Contributor Author

@mtrezza Regarding the perf regression on Query.find (concurrent, GC pressure):

The benchmark suite uses the Parse JS SDK over HTTP (Parse.serverURL = 'http://localhost:1337/parse') — it does not enable directAccess. The JSON.parse(JSON.stringify()) changes in ParseServerRESTController are only exercised in directAccess mode, so they are not hit during benchmarks.

The latest CI run shows:

Benchmark Baseline PR Change Status
Query.find (concurrent, GC pressure) 304.76 ms 468.67 ms +53.8%

All other benchmarks are within normal variance (< 7%). The concurrent GC pressure test is inherently noisy since it depends on V8 garbage collection timing across 10 simultaneous queries each fetching 3,000 large (~8KB) documents. The fluctuation between runs (41.1% in the first run, 53.8% in the re-run) also suggests CI environment noise rather than a code-related regression.

That said, to address the performance concern, I can replace JSON.parse(JSON.stringify()) with an in-place stripUndefined that simply deletes keys with undefined values recursively — no object copying at all. The data flowing through ParseServerRESTController is already Parse-encoded (no raw Date objects or special types), so an in-place delete is equivalent to JSON.parse(JSON.stringify()) for this use case while avoiding allocation overhead entirely.

@mtrezza

mtrezza commented Apr 14, 2026

Copy link
Copy Markdown
Member

A GC perf test can be flaky, but not fail on every CI run. That's suspicious. Also, the perf arguments don't make much sense. I suggest you try another solution.

@yog27ray

Copy link
Copy Markdown
Contributor Author

@mtrezza Replaced JSON.parse(JSON.stringify()) with an in-place stripUndefined that recursively deletes undefined keys and converts undefined array elements to null — mutating the object directly without any allocation.

Both approaches produce identical results in ParseServerRESTController because the data flowing through it is already Parse-encoded — plain objects, arrays, and primitives (strings, numbers, booleans, null). There are no Date objects, RegExp, Map, Set, or objects with custom toJSON() methods that would cause JSON.stringify to behave differently from a simple recursive walk. The only divergence between JSON.stringify and a plain traversal is how it handles those special types, which don't exist at this layer.

The performance advantage: when no undefined values are present (the common case), the function traverses and returns without creating any new objects. When undefined does exist, it just deletes the key or assigns null in-place — no serialize + parse overhead, no new object tree allocation, no GC pressure.

Avoid full deep-copy on every request/response by mutating in-place.
This eliminates unnecessary allocations and GC pressure for the common
case where no undefined values exist.
@yog27ray
yog27ray force-pushed the fix/directaccess-undefined-to-null branch from f6ea238 to 0e56fdf Compare April 16, 2026 03:37
@mtrezza

mtrezza commented Apr 16, 2026

Copy link
Copy Markdown
Member

Perf job passes now.

converts undefined array elements to null

What is this convention based on?

@yog27ray

Copy link
Copy Markdown
Contributor Author

This matches JSON.stringify behavior. Per the ECMAScript specification (and MDN):

  • In objects, undefined values cause the property to be omitted
  • In arrays, undefined values are converted to null

For example:

JSON.stringify({ a: undefined, b: 1 })       // '{"b":1}'        — key omitted
JSON.stringify([1, undefined, 3])             // '[1,null,3]'     — undefined → null

Since the goal of stripUndefined is to make directAccess behave identically to the HTTP path (where JSON.stringify is applied during serialization), the function mirrors both behaviors: deleting undefined object keys and converting undefined array elements to null.

@yog27ray

Copy link
Copy Markdown
Contributor Author

@mtrezza any further changes required.

@yog27ray
yog27ray requested a review from mtrezza May 5, 2026 02:29
@yog27ray

Copy link
Copy Markdown
Contributor Author

@mtrezza any update on this

@yog27ray

yog27ray commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

@mtrezza is there any changes required?

@mtrezza

mtrezza commented Jun 3, 2026

Copy link
Copy Markdown
Member

Requires further review... the issue is that directAccess is lacking proper test coverage, so we're operating in the dark here.

@yog27ray

Copy link
Copy Markdown
Contributor Author

Requires further review... the issue is that directAccess is lacking proper test coverage, so we're operating in the dark here.

@mtrezza, thanks for the review. On the coverage concern — I've now added test cases covering this path in directAccess mode, for both the request side (undefined values previously stored as null, which breaks doesNotExist/exists queries) and the response side (undefined values leaking to the caller). That should make this path easier to reason about and guard against future regressions.

For what it's worth, we've also been running this fix in production via patch-package and it has been working reliably. As it stands, the current behaviour effectively blocks a number of users from using directAccess, so this PR is correcting a genuine bug rather than introducing new behaviour. Happy to add more cases if there are specific scenarios you'd like covered.

@mtrezza

mtrezza commented Jun 13, 2026

Copy link
Copy Markdown
Member

Thanks for the details. I'm referring to the whole directAccess feature; it's lacking proper coverage; virtually all tests run with directAccess disabled. So directAcess related changes take some time to merge.

@yog27ray

Copy link
Copy Markdown
Contributor Author

@mtrezza any thing that i can help with to make this PR merge.

@mtrezza

mtrezza commented Aug 21, 2026

Copy link
Copy Markdown
Member

Merged alpha to check CI state

@yog27ray

Copy link
Copy Markdown
Contributor Author

@mtrezza All checks have passed on the latest run against alpha, including the Benchmarks job that was previously flagging the perf regression. Let me know if there's anything else needed to move this forward — happy to expand the directAccess test coverage further if that helps.

@yog27ray

yog27ray commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

@mtrezza can we get this PR merged ?

@mtrezza

mtrezza commented Sep 9, 2026

Copy link
Copy Markdown
Member

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
⚠️ Action not completed

Head commit changed.

@yog27ray

Copy link
Copy Markdown
Contributor Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

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.

4 participants