Skip to content

Add serialization support for QueryBuilder where/sort/minus clauses#60

Merged
flyon merged 4 commits intodevfrom
claude/fix-tojson-where-clause-OVMkW
Apr 6, 2026
Merged

Add serialization support for QueryBuilder where/sort/minus clauses#60
flyon merged 4 commits intodevfrom
claude/fix-tojson-where-clause-OVMkW

Conversation

@flyon
Copy link
Copy Markdown
Member

@flyon flyon commented Apr 6, 2026

Summary

This PR adds comprehensive serialization and deserialization support for QueryBuilder's where clauses, sort keys, and minus entries. Previously, these complex runtime structures containing live object references could not be round-tripped through JSON. Now they are converted to plain JSON-safe representations that preserve all query semantics.

Key Changes

  • New QueryBuilderSerialization.ts module: Provides serialization/deserialization helpers for:

    • WherePath structures (evaluation paths, AND/OR combinations, expression nodes)
    • SortByPath structures (property paths with direction)
    • RawMinusEntry structures (shape references, where clauses, property paths)
    • All nested QueryArg types (primitives, dates, node references, nested where clauses, arg paths)
  • Updated QueryBuilder.toJSON():

    • Evaluates where/sort/minus callbacks and serializes the resulting structures
    • Merges preload entries into the FieldSet before serialization for consistent IR
    • Preserves nullSubject and pendingContextName flags
    • Handles both callback-based and pre-evaluated data
  • Updated QueryBuilder.fromJSON():

    • Deserializes where/sort/minus clauses back into runtime structures
    • Stores deserialized data in private fields (_where, _sortBy, _rawMinusEntries)
    • Uses deserialized data during build() when callbacks are unavailable
    • Restores nullSubject and pendingContextName flags
  • Updated QueryBuilder.build():

    • Falls back to pre-evaluated data when callbacks are not available
    • Enables queries restored from JSON to produce identical IR
  • Comprehensive test coverage in serialization.test.ts:

    • Where clause serialization (simple equals, nodeRef args, AND/OR combinations, nested paths)
    • Sort key serialization and round-trip validation
    • Minus entry serialization (shape types and where clauses)
    • Complex round-trip scenarios with multiple clauses
    • Preload serialization and merging behavior
    • JSON string serialization (full stringify/parse cycle)

Implementation Details

  • Serialization converts live object references (PropertyShape, ExpressionNode, etc.) to JSON-safe IDs and metadata
  • Deserialization reconstructs runtime structures by looking up shapes and properties by ID
  • The approach maintains backward compatibility: queries without where/sort/minus clauses serialize/deserialize as before
  • Preloads are merged into the FieldSet during serialization, ensuring consistent IR on deserialization
  • All round-trip tests verify that sanitize(restored.build()) equals sanitize(original.build())

https://claude.ai/code/session_01P6n2XLm5DSugoa8RWN97yy

claude added 2 commits April 6, 2026 13:08
…her missing fields

QueryBuilder.toJSON() was silently dropping where clauses, sort keys,
minus entries, nullSubject, and pendingContextName. This meant any
query with .where() would lose its filter when round-tripping through
JSON serialization.

- Add QueryBuilderSerialization.ts with serialize/deserialize helpers
  for WherePath, SortByPath, RawMinusEntry, and QueryArg types
- Update QueryBuilderJSON type with where, sortBy, minusEntries,
  nullSubject, and pendingContextName fields
- Update toJSON() to evaluate callbacks and serialize all fields
- Update fromJSON() to deserialize and restore all fields via
  pre-evaluated data (_where, _sortBy, _rawMinusEntries)
- Update _buildDirectRawInput() to use pre-evaluated data as fallback
  when callbacks aren't available (i.e. after JSON deserialization)
- Add 18 round-trip serialization tests confirming identical IR output

https://claude.ai/code/session_01P6n2XLm5DSugoa8RWN97yy
…lect

Preloads were the last remaining field not serialized in toJSON(). Fixed by:
- Merging preload entries into the FieldSet at serialization time (same
  merge logic as _buildDirectRawInput), so preloaded component fields
  appear as subSelect entries in the JSON
- Adding preloadSubSelect handling in FieldSet.toJSON() so it serializes
  identically to subSelect (both produce the same IR)
- Adding 3 round-trip tests confirming preload serialization

https://claude.ai/code/session_01P6n2XLm5DSugoa8RWN97yy
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 6, 2026

⚠️ No changeset found. If this PR should trigger a release, run npx changeset and commit the generated file.

If this change doesn't need a release (docs, CI config, etc.), you can ignore this message.

claude added 2 commits April 6, 2026 13:28
- Extract _fieldsWithPreloads() from duplicated preload merge logic
  in toJSON() and _buildDirectRawInput()
- Extract _evaluateMinusEntries() from duplicated minus entry
  evaluation logic, reusing a single proxy instance
- Fix WhereMethods cast from `as any` to `as WhereMethods`
- Remove unused PropertyPath import from QueryBuilderSerialization.ts
- Remove redundant inline comments that restated the code
- Add changeset patch for the toJSON fix

https://claude.ai/code/session_01P6n2XLm5DSugoa8RWN97yy
@flyon flyon merged commit 619f580 into dev Apr 6, 2026
4 checks passed
@flyon flyon deleted the claude/fix-tojson-where-clause-OVMkW branch April 6, 2026 13:39
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