From 3770abc638762205e52ddc2a731b99d9e985a69e Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 21 Sep 2026 21:29:03 +0200 Subject: [PATCH 01/23] Measure and optimize response conversion with regression coverage --- .github/workflows/bindings.yml | 10 + .gitignore | 6 +- .../Test_conversionContract-tests.js | 131 ++++ .../__tests__/utils-contract-tests.js | 389 ++++++++++++ .../rescript-relay/__tests__/utils-tests.js | 9 +- packages/rescript-relay/benchmarks/README.md | 79 +++ .../rescript-relay/benchmarks/conversion.js | 130 ++++ .../rescript-relay/benchmarks/fixtures.js | 119 ++++ .../benchmarks/results/README.md | 27 + .../benchmarks/results/baseline.json | 94 +++ .../benchmarks/results/optimized.json | 94 +++ .../rescript-relay/jest.conversion.config.js | 18 + packages/rescript-relay/package.json | 5 +- packages/rescript-relay/src/utils.js | 593 +++++++----------- 14 files changed, 1316 insertions(+), 388 deletions(-) create mode 100644 packages/rescript-relay/__tests__/Test_conversionContract-tests.js create mode 100644 packages/rescript-relay/__tests__/utils-contract-tests.js create mode 100644 packages/rescript-relay/benchmarks/README.md create mode 100644 packages/rescript-relay/benchmarks/conversion.js create mode 100644 packages/rescript-relay/benchmarks/fixtures.js create mode 100644 packages/rescript-relay/benchmarks/results/README.md create mode 100644 packages/rescript-relay/benchmarks/results/baseline.json create mode 100644 packages/rescript-relay/benchmarks/results/optimized.json create mode 100644 packages/rescript-relay/jest.conversion.config.js diff --git a/.github/workflows/bindings.yml b/.github/workflows/bindings.yml index 4e4e23ea..c9c602bb 100644 --- a/.github/workflows/bindings.yml +++ b/.github/workflows/bindings.yml @@ -41,3 +41,13 @@ jobs: - name: Test run: | yarn test:ci + ENABLE_PERSISTING=true yarn test:ci + yarn test:conversion + - name: Conversion benchmark (informational) + run: yarn bench:conversion --samples 7 --duration 20 --output conversion-benchmark.json + - uses: actions/upload-artifact@v4 + with: + name: conversion-performance + path: | + packages/rescript-relay/conversion-benchmark.json + packages/rescript-relay/coverage/conversion/ diff --git a/.gitignore b/.gitignore index 1beb720c..d87877ec 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,8 @@ _opam *.bs.js rescript-relay-compiler .now -.DS_Store \ No newline at end of file +.DS_Store +# Local conversion coverage and profiling output +coverage/ +*.cpuprofile +conversion-benchmark.json diff --git a/packages/rescript-relay/__tests__/Test_conversionContract-tests.js b/packages/rescript-relay/__tests__/Test_conversionContract-tests.js new file mode 100644 index 00000000..228ad40b --- /dev/null +++ b/packages/rescript-relay/__tests__/Test_conversionContract-tests.js @@ -0,0 +1,131 @@ +require("@testing-library/jest-dom/extend-expect"); +const React = require("react"); +const { render, screen, act } = require("@testing-library/react"); +const { RelayEnvironmentProvider } = require("react-relay"); +const { createMockEnvironment } = require("relay-test-utils"); +const { createOperationDescriptor } = require("relay-runtime"); +const Scalar = require("./Test_customScalars.bs"); +const Fragment = require("./Test_fragment.bs"); +const scalarNode = + require("./__generated__/TestCustomScalarsQuery_graphql.bs").node; +const fragmentNode = + require("./__generated__/TestFragmentQuery_graphql.bs").node; + +function mount(environment, Component) { + const tree = () => + React.createElement( + RelayEnvironmentProvider, + { environment }, + React.createElement( + React.Suspense, + { fallback: "Loading" }, + React.createElement(Component), + ), + ); + const view = render(tree()); + return () => view.rerender(tree()); +} + +test("compiled query converts nested scalar lists and unions after store updates without changing the store", () => { + const environment = createMockEnvironment(); + const variables = { + number: [2], + beforeDate: new Date("2018-01-01T00:00:00Z"), + }; + const wireVariables = Scalar.Query.convertVariables(variables); + expect(wireVariables).toEqual({ + number: 2, + beforeDate: "2018-01-01T00:00:00.000Z", + }); + const operation = createOperationDescriptor(scalarNode, wireVariables); + const date1 = "2020-01-01T00:00:00.000Z"; + const date2 = "2021-01-01T00:00:00.000Z"; + const payload = (date) => ({ + loggedInUser: { + id: "viewer", + createdAt: date, + friends: [{ id: "friend", createdAt: date }], + }, + member: { __typename: "User", id: "member", createdAt: date }, + }); + environment.commitPayload(operation, payload(date1)); + let converted; + function Probe() { + converted = Scalar.Query.use(variables, "store-only"); + return React.createElement( + "div", + null, + converted.loggedInUser.friends[0].createdAt.toISOString(), + ); + } + const rerender = mount(environment, Probe); + expect(screen.getByText(date1)).toBeInTheDocument(); + expect(converted.member.createdAt).toEqual(new Date(date1)); + expect( + environment.lookup(operation.fragment).data.loggedInUser.friends[0] + .createdAt, + ).toBe(date1); + const first = converted; + rerender(); + expect(converted).toBe(first); // The real binding's useMemo still applies. + act(() => environment.commitPayload(operation, payload(date2))); + expect(screen.getByText(date2)).toBeInTheDocument(); + expect(converted).not.toBe(first); + expect(converted.member.createdAt).toEqual(new Date(date2)); + expect(first.loggedInUser.friends[0].createdAt).toEqual(new Date(date1)); + expect(environment.lookup(operation.fragment).data.member.createdAt).toBe( + date2, + ); +}); + +test("compiled fragment refs can be consumed by nested and plural hooks across nullable store updates", () => { + const environment = createMockEnvironment(); + const operation = createOperationDescriptor(fragmentNode, {}); + const payload = (status) => ({ + loggedInUser: { + id: "viewer", + firstName: "Viewer", + lastName: "Last", + onlineStatus: status, + }, + users: { + edges: [ + { node: { id: "friend", firstName: "Friend", onlineStatus: status } }, + ], + }, + }); + environment.commitPayload(operation, payload("Online")); + let result; + function Probe() { + const query = Fragment.Query.use(undefined, "store-only"); + const fragment = Fragment.Fragment.use(query.loggedInUser.fragmentRefs); + const nested = Fragment.SubFragment.use(fragment.fragmentRefs); + const plural = Fragment.PluralFragment.use( + query.users.edges.map((edge) => edge.node.fragmentRefs), + ); + result = { query, fragment, nested, plural }; + return React.createElement( + "div", + null, + `${nested.lastName}:${plural[0].onlineStatus ?? "none"}`, + ); + } + mount(environment, Probe); + expect(screen.getByText("Last:Online")).toBeInTheDocument(); + expect(result.fragment.updatableFragmentRefs).toBe( + result.fragment.fragmentRefs, + ); + expect(result.query.users.edges[0].node.updatableFragmentRefs).toBe( + result.query.users.edges[0].node.fragmentRefs, + ); + act(() => environment.commitPayload(operation, payload(null))); + expect(screen.getByText("Last:none")).toBeInTheDocument(); + expect(result.fragment.onlineStatus).toBeUndefined(); + expect(result.plural[0].onlineStatus).toBeUndefined(); + // The refs still contain the wire value; only the returned data is converted. + expect(result.query.users.edges[0].node.fragmentRefs.onlineStatus).toBeNull(); + expect( + environment.lookup(operation.fragment).data.users.edges[0].node + .onlineStatus, + ).toBeNull(); +}); diff --git a/packages/rescript-relay/__tests__/utils-contract-tests.js b/packages/rescript-relay/__tests__/utils-contract-tests.js new file mode 100644 index 00000000..c21464ff --- /dev/null +++ b/packages/rescript-relay/__tests__/utils-contract-tests.js @@ -0,0 +1,389 @@ +const { traverser } = require("../src/utils"); + +function freeze(value) { + if (value && typeof value === "object" && !Object.isFrozen(value)) { + Object.values(value).forEach(freeze); + Object.freeze(value); + } + return value; +} + +describe.each([undefined, null])( + "conversion contract (nullable=%s)", + (nullable) => { + test("absent roots, absent instructions, empty and sparse arrays", () => { + expect(traverser(null, null, null, nullable)).toBe(nullable); + expect(traverser(undefined, null, null, nullable)).toBe(nullable); + expect(traverser({}, null, null, nullable)).toStrictEqual({}); + const values = [null, , undefined, 0, false, ""]; + const result = traverser({ values }, null, null, nullable); + expect(result.values).toStrictEqual([nullable, , nullable, 0, false, ""]); + expect(1 in result.values).toBe(false); + expect(traverser([], {}, {}, nullable)).toStrictEqual([]); + }); + + test("frozen inputs, opaque Relay metadata and exact fragment snapshots", () => { + const metadata = { value: null }; + metadata.cycle = metadata; + const input = { + value: null, + nested: { value: null }, + __fragments: metadata, + __fragmentOwner: metadata, + __id: null, + __typename: "User", + __relay_internal__pv__flag: null, + }; + // Freeze the cyclic metadata separately. + Object.freeze(metadata); + freeze(input); + const result = traverser( + input, + { __root: { "": { f: "" }, nested: { f: "" } } }, + {}, + nullable, + ); + expect(result.value).toBe(nullable); + expect(result.__id).toBe(nullable); + expect(result.__relay_internal__pv__flag).toBe(nullable); + expect(result.__fragments).toBe(metadata); + expect(result.__fragmentOwner).toBe(metadata); + expect(result.fragmentRefs).toStrictEqual(input); + expect(result.updatableFragmentRefs).toBe(result.fragmentRefs); + expect(result.nested.fragmentRefs).toStrictEqual(input.nested); + expect(result.nested.updatableFragmentRefs).toBe( + result.nested.fragmentRefs, + ); + expect(result.fragmentRefs).not.toHaveProperty("fragmentRefs"); + expect(input.value).toBeNull(); + expect(input.nested).toStrictEqual({ value: null }); + }); + + test("enum arrays skip nulls and call converters once per non-null element", () => { + const convert = jest.fn((v) => `converted:${v}`); + const input = freeze({ items: ["A", null, "B"], sibling: "C" }); + const result = traverser( + input, + { __root: { items: { e: "enum" }, sibling: { e: "enum" } } }, + { enum: convert }, + nullable, + ); + expect(result).toStrictEqual({ + items: ["converted:A", nullable, "converted:B"], + sibling: "converted:C", + }); + expect(convert.mock.calls).toEqual([["A"], ["B"], ["C"]]); + }); + + test("missing converters leave values available for nullable traversal", () => { + const result = traverser( + freeze({ item: { value: null }, items: [{ value: null }] }), + { __root: { item: { c: "missing" }, items: { u: "missing" } } }, + {}, + nullable, + ); + expect(result).toStrictEqual({ + item: { value: nullable }, + items: [{ value: nullable }], + }); + }); + + test("recursive input unions and arrays use their named instruction root", () => { + const convert = jest.fn((v) => v.toLowerCase()); + const input = freeze({ + items: [{ __$inputUnion: "choice", _0: { status: "A" } }, null], + tree: { status: "B", children: [{ status: "C", children: [] }] }, + }); + const result = traverser( + input, + { + __root: { items: { r: "Input" }, tree: { r: "Tree" } }, + Input: { choice_status: { e: "enum" } }, + Tree: { status: { e: "enum" }, children: { r: "Tree" } }, + }, + { enum: convert }, + nullable, + ); + expect(result).toStrictEqual({ + items: [{ choice: { status: "a" } }, nullable], + tree: { status: "b", children: [{ status: "c", children: [] }] }, + }); + expect(convert.mock.calls).toEqual([["A"], ["B"], ["C"]]); + }); + + test("root union arrays dispatch each member independently", () => { + const union = jest.fn((v) => v); + const input = freeze([ + { __typename: "User", value: null }, + null, + { __typename: "Page", value: null }, + { __typename: "User", value: "ok" }, + ]); + const result = traverser( + input, + { __root: { "": { u: "union" }, User: { f: "" } } }, + { union }, + nullable, + ); + expect(result[0].fragmentRefs).toStrictEqual(input[0]); + expect(result[0].value).toBe(nullable); + expect(result[1]).toBe(nullable); + expect(result[2]).toStrictEqual({ __typename: "Page", value: nullable }); + expect(result[3].fragmentRefs).toStrictEqual(input[3]); + expect(union).toHaveBeenCalledTimes(3); + }); + + test("custom scalar results remain opaque, including falsey values", () => { + for (const output of [ + false, + 0, + "", + null, + undefined, + { value: null }, + [null], + ]) { + const convert = jest.fn(() => output); + const result = traverser( + freeze({ scalar: "input", after: null }), + { __root: { scalar: { c: "scalar" } } }, + { scalar: convert }, + nullable, + ); + expect(result.scalar).toBe(output); + expect(result.after).toBe(nullable); + expect(convert.mock.calls).toEqual([["input"]]); + } + }); + + test("blocked JSON retains identity and nested nulls", () => { + const json = freeze({ value: null, nested: [null] }); + const result = traverser( + freeze({ json, items: [json, null], after: null }), + { __root: { json: { b: "" }, items: { b: "a" } } }, + {}, + nullable, + ); + expect(result.json).toBe(json); + expect(result.items[0]).toBe(json); + expect(result.items[1]).toBe(nullable); + expect(result.after).toBe(nullable); + }); + + test("nested union conversion runs in the correct order in each direction", () => { + const events = []; + const union = (v) => { + events.push("union"); + return { ...v, marker: true }; + }; + const scalar = (v) => { + events.push("scalar"); + return v + 1; + }; + const result = traverser( + freeze({ item: { __typename: "User", value: 1 } }), + { __root: { item: { u: "union" }, item_User_value: { c: "scalar" } } }, + { union, scalar }, + nullable, + ); + expect(result).toStrictEqual({ + item: { __typename: "User", value: 2, marker: true }, + }); + expect(events).toStrictEqual( + nullable === null ? ["union", "scalar"] : ["scalar", "union"], + ); + }); + }, +); + +describe("conversion sharing and repeatability", () => { + test("unchanged roots, objects, lists and nulls retain identity", () => { + const root = freeze({ + id: "1", + nested: { value: 3 }, + list: [{ value: 2 }, "x"], + empty: [], + }); + expect(traverser(root)).toBe(root); + expect(traverser(root.list)).toBe(root.list); + expect(traverser(root.empty)).toBe(root.empty); + const nullable = freeze({ value: null, list: [null] }); + expect(traverser(nullable, {}, {}, null)).toBe(nullable); + }); + + test("copies only ancestors of changes and preserves untouched siblings", () => { + const root = freeze({ + left: { value: 1 }, + right: { value: null }, + list: [{ value: 1 }, { value: null }], + }); + const result = traverser(root); + expect(result).not.toBe(root); + expect(result.left).toBe(root.left); + expect(result.right).not.toBe(root.right); + expect(result.list).not.toBe(root.list); + expect(result.list[0]).toBe(root.list[0]); + expect(result.list[1]).not.toBe(root.list[1]); + }); + + test("does not cache mutable inputs, instructions or converter closures", () => { + const root = { value: 1 }; + const maps = { __root: { value: { c: "scalar" } } }; + let offset = 1; + const converters = { scalar: (v) => v + offset }; + expect(traverser(root, maps, converters).value).toBe(2); + offset = 2; + expect(traverser(root, maps, converters).value).toBe(3); + root.value = 2; + expect(traverser(root, maps, converters).value).toBe(4); + maps.__root.value = {}; + expect(traverser(root, maps, converters).value).toBe(2); + }); + + test("mixed union lists convert untyped siblings independently", () => { + const input = freeze({ + items: [{ __typename: "User", value: null }, { value: null }, null], + }); + const result = traverser( + input, + { __root: { items: { u: "union" } } }, + { union: (v) => v }, + ); + expect(result).toStrictEqual({ + items: [ + { __typename: "User", value: undefined }, + { value: undefined }, + undefined, + ], + }); + }); + + test("fragment refs in lists stay raw and share their updatable ref", () => { + const input = freeze({ items: [{ value: null, nested: { value: null } }] }); + const result = traverser(input, { __root: { items: { f: "" } } }); + expect(result.items[0].fragmentRefs).toStrictEqual(input.items[0]); + expect(result.items[0].fragmentRefs.nested).toBe(input.items[0].nested); + expect(result.items[0].updatableFragmentRefs).toBe( + result.items[0].fragmentRefs, + ); + expect(result.items[0].nested.value).toBeUndefined(); + }); + + test("fragment refs on opaque array elements do not traverse JSON", () => { + const input = freeze({ items: [{ value: null }] }); + const result = traverser(input, { __root: { items: { f: "", b: "a" } } }); + expect(result.items[0].value).toBeNull(); + expect(result.items[0].fragmentRefs).toStrictEqual(input.items[0]); + }); + + test("sparse plural roots preserve holes", () => { + const input = freeze([{ value: null }, , null]); + expect(traverser(input)).toStrictEqual([{ value: undefined }, , undefined]); + }); + + test("converter exceptions propagate without mutating the input", () => { + const input = freeze({ before: null, value: "bad" }); + const error = new Error("bad scalar"); + expect(() => + traverser( + input, + { __root: { value: { c: "scalar" } } }, + { + scalar: () => { + throw error; + }, + }, + ), + ).toThrow(error); + expect(input.before).toBeNull(); + }); + + test("deterministic generated trees match an independent nullable conversion model", () => { + let seed = 0x12345678; + const random = () => { + seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0; + return seed; + }; + function generate(depth) { + if (!depth) + return [null, undefined, false, 0, "", "text", 42][random() % 7]; + return { + value: generate(0), + child: generate(depth - 1), + items: Array.from({ length: random() % 5 }, () => generate(depth - 1)), + }; + } + function reference(value, nullable) { + if (value == null) return nullable; + if (Array.isArray(value)) return value.map((v) => reference(v, nullable)); + if (typeof value === "object") + return Object.fromEntries( + Object.entries(value).map(([k, v]) => [k, reference(v, nullable)]), + ); + return value; + } + for (let i = 0; i < 100; i++) { + const input = freeze(generate(3)); + for (const nullable of [null, undefined]) { + expect(traverser(input, {}, {}, nullable)).toStrictEqual( + reference(input, nullable), + ); + } + } + }); +}); + +test("generated combinations of enums, scalar lists, recursion and union members have exact outputs", () => { + for (let size = 0; size < 25; size++) { + const rows = Array.from({ length: size }, (_, i) => ({ + __typename: i % 2 ? "User" : "Page", + status: i % 3 ? "ON" : null, + scalar: String(i), + json: { nullable: null }, + })); + const input = freeze({ rows, after: null }); + for (const nullable of [undefined, null]) { + let scalarCalls = 0; + const converters = { + union: (v) => v, + enum: (v) => v.toLowerCase(), + scalar: (v) => { + scalarCalls++; + return Number(v); + }, + }; + const instructions = { rows: { u: "union" } }; + for (const member of ["User", "Page"]) { + instructions[`rows_${member}_status`] = { e: "enum" }; + instructions[`rows_${member}_scalar`] = { c: "scalar" }; + instructions[`rows_${member}_json`] = { b: "" }; + } + expect( + traverser(input, { __root: instructions }, converters, nullable), + ).toStrictEqual({ + rows: rows.map((row) => ({ + ...row, + status: row.status === null ? nullable : "on", + scalar: Number(row.scalar), + })), + after: nullable, + }); + expect(scalarCalls).toBe(size); + } + } +}); + +test("recursive array roots are converted exactly once, including nullable scalar results", () => { + const input = freeze({ items: [{ value: "wire" }], after: null }); + const output = { value: null }; + const scalar = jest.fn(() => output); + const result = traverser( + input, + { __root: { items: { r: "Input" } }, Input: { value: { c: "scalar" } } }, + { scalar }, + ); + expect(result.items[0].value).toBe(output); + expect(result.items[0].value.value).toBeNull(); + expect(result.after).toBeUndefined(); + expect(scalar).toHaveBeenCalledTimes(1); +}); diff --git a/packages/rescript-relay/__tests__/utils-tests.js b/packages/rescript-relay/__tests__/utils-tests.js index 8e5f0336..988817f6 100644 --- a/packages/rescript-relay/__tests__/utils-tests.js +++ b/packages/rescript-relay/__tests__/utils-tests.js @@ -85,13 +85,8 @@ describe("conversion", () => { undefined ); - try { - expect(JSON.stringify(traversedObj)).toBeDefined(); - } catch (e) { - console.error(e); - } - - expect.assertions(1); + expect(() => JSON.stringify(traversedObj)).not.toThrow(); + expect(traversedObj.fragmentRefs).not.toHaveProperty("fragmentRefs"); }); it("handles converting enums", () => { diff --git a/packages/rescript-relay/benchmarks/README.md b/packages/rescript-relay/benchmarks/README.md new file mode 100644 index 00000000..b81265b8 --- /dev/null +++ b/packages/rescript-relay/benchmarks/README.md @@ -0,0 +1,79 @@ +# Response conversion performance + +Run from `packages/rescript-relay`: + +```sh +yarn test:all +yarn bench:conversion --output /tmp/conversion-after.json +``` + +`test:all` compiles the checked-in generated Relay artifacts and ReScript bindings, +then runs the mounted React/Relay tests, the separate persisted-query suite, and +utility tests with coverage thresholds. Build the PPX first as in the bindings CI +workflow (`opam install . --deps-only`, then `opam exec -- dune build +bin/RescriptRelayPpxApp.exe` in `rescript-relay-ppx`). No Relay compiler regeneration +is needed unless GraphQL selections change. + +For a before/after comparison using the **same fixtures and harness**: + +```sh +git show 520cac4933c118a85cf0dffcd1a19a5dba34ad4f:packages/rescript-relay/src/utils.js > /tmp/utils-before.cjs +yarn bench:conversion --implementation /tmp/utils-before.cjs --output /tmp/conversion-before.json +yarn bench:conversion --compare /tmp/conversion-before.json --output /tmp/conversion-after.json +``` + +Run those commands sequentially on an otherwise idle machine, with the same Node +version. Repeat in reversed order to check for warmup, CPU frequency, or load +bias. `--samples` (default 15) and `--duration` (default 40 ms per sample) control +measurement length. Each case calibrates and warms up before collecting samples; +reports include median, p10/p90, throughput, runtime, CPU, and fixture version. +Fixtures cover both response reads and recursive input writes. Correctness and +input immutability are asserted before timing; expected results are independent +of the instruction interpreter. Raw fragment refs are verified by the tests, +not by comparing to older implementations that incorrectly traversed them. + +`newOutputObjects` counts unique objects reachable from the output that were not +in the input, including arrays, dates, and fragment-ref snapshots. It is a stable +measure of output allocations, **not** total allocations, heap bytes, or peak +memory. It excludes temporary objects that are already unreachable. CI uploads +this report and conversion coverage; timings are informational, while correctness +and coverage failures block CI. + +For CPU and GC investigation: + +```sh +node --cpu-prof --cpu-prof-dir=/tmp benchmarks/conversion.js +node --trace-gc benchmarks/conversion.js > /tmp/conversion-gc.log +``` + +Open the CPU profile in a compatible profiler. Profile baseline and candidate +separately; profiling changes timings. These are conversion microbenchmarks, +not end-to-end React latency measurements. The mounted tests exercise actual +compiled query/fragment hooks and store updates without relying on timing. + +## Implementation and compatibility + +The converter carries encoded string prefixes instead of constructing and +joining path arrays per field. Plain scalar fields take a short path. Lists are +traversed once, each member independently, with lazy copying only when an element +changes. Objects likewise retain identity when nothing changes. Generated +fragment refs are attached while traversing the original object, so they stay raw +and are not visited as new data. Both fragment-ref properties share one snapshot. + +This also removes the old extra recursive-array traversal and the list-wide +union flag that could cause untyped siblings to be skipped. Conversion does not +cache inputs, instruction maps, converter maps, or callback results. Changes to +those values remain visible on subsequent calls, without retaining Relay data. + +Null/undefined handling, opaque JSON blocking, input unions, nested option +markers, custom scalar boundaries, and converter order are tested in both +directions. In particular, `ca` deliberately retains its existing `Array.map` +semantics: callbacks receive `(value, index, array)`, including null elements. +Changing nullable custom scalar element behavior is outside this optimization. +Unchanged roots and arrays may now be returned by identity; consumers must treat +converted responses as immutable, just like Relay snapshots. + +The existing bindings already memoize conversions with `useMemo` keyed by the +Relay snapshot. The mounted regression tests verify unchanged rerenders reuse +that result and store updates produce freshly converted data. No hook-level +cache or dependency changes were needed. diff --git a/packages/rescript-relay/benchmarks/conversion.js b/packages/rescript-relay/benchmarks/conversion.js new file mode 100644 index 00000000..3512acb8 --- /dev/null +++ b/packages/rescript-relay/benchmarks/conversion.js @@ -0,0 +1,130 @@ +#!/usr/bin/env node +const { performance } = require("perf_hooks"); +const os = require("os"); +const path = require("path"); +const fs = require("fs"); +const assert = require("assert/strict"); +const v8 = require("v8"); +const { cases, converters } = require("./fixtures"); +const args = process.argv.slice(2); +const option = (name) => { + const i = args.indexOf(name); + return i < 0 ? undefined : args[i + 1]; +}; +const implementation = option("--implementation"); +const { traverser } = require( + implementation ? path.resolve(implementation) : "../src/utils", +); +const samples = Number(option("--samples") || 15); +const duration = Number(option("--duration") || 40); +if ( + !Number.isInteger(samples) || + samples < 3 || + !Number.isFinite(duration) || + duration <= 0 +) { + throw new Error( + "Use --samples >= 3 and --duration > 0 (milliseconds per sample).", + ); +} +function dataOnly(value) { + if (Array.isArray(value)) return value.map(dataOnly); + if (!value || typeof value !== "object" || value instanceof Date) + return value; + return Object.fromEntries( + Object.entries(value) + .filter( + ([key]) => key !== "fragmentRefs" && key !== "updatableFragmentRefs", + ) + .map(([key, v]) => [key, dataOnly(v)]), + ); +} +function objects(value, seen = new Set()) { + if (value && typeof value === "object" && !seen.has(value)) { + seen.add(value); + Object.values(value).forEach((v) => objects(v, seen)); + } + return seen; +} +let sink; +function batch(fixture, count) { + const start = performance.now(); + for (let i = 0; i < count; i++) + sink = traverser(fixture.root, fixture.maps, converters, fixture.nullable); + return performance.now() - start; +} +const results = cases.map((fixture) => { + const before = v8.deserialize(v8.serialize(fixture.root)); + const converted = traverser( + fixture.root, + fixture.maps, + converters, + fixture.nullable, + ); + assert.deepStrictEqual(dataOnly(converted), fixture.expected, fixture.name); + assert.deepStrictEqual( + fixture.root, + before, + fixture.name + ": input mutated", + ); + const inputObjects = objects(fixture.root); + const newOutputObjects = [...objects(converted)].filter( + (v) => !inputObjects.has(v), + ).length; + // Calibrate outside the measured samples; warm the same call site first. + let iterations = 100; + while (batch(fixture, iterations) < duration) iterations *= 2; + const values = Array.from( + { length: samples }, + () => (batch(fixture, iterations) * 1e6) / iterations, + ).sort((a, b) => a - b); + const median = values[Math.floor(values.length / 2)]; + return { + name: fixture.name, + iterations, + newOutputObjects, + medianNs: median, + p10Ns: values[Math.floor(values.length * 0.1)], + p90Ns: values[Math.floor(values.length * 0.9)], + opsPerSecond: 1e9 / median, + }; +}); +const report = { + fixtureVersion: 1, + node: process.version, + platform: `${os.platform()} ${os.arch()}`, + cpu: os.cpus()[0].model, + samples, + durationMs: duration, + implementation: implementation || "src/utils.js", + results, +}; +console.table( + results.map((r) => ({ + case: r.name, + "median ns": Math.round(r.medianNs), + "p10 ns": Math.round(r.p10Ns), + "p90 ns": Math.round(r.p90Ns), + "ops/sec": Math.round(r.opsPerSecond), + "new output objects": r.newOutputObjects, + })), +); +const baseline = option("--compare"); +if (baseline) { + const previous = JSON.parse(fs.readFileSync(baseline, "utf8")); + if (previous.fixtureVersion !== report.fixtureVersion) + throw new Error("Benchmark fixture versions differ"); + console.table( + results.map((r) => { + const old = previous.results.find((x) => x.name === r.name); + return { + case: r.name, + speedup: old ? (old.medianNs / r.medianNs).toFixed(2) + "x" : "n/a", + }; + }), + ); +} +if (option("--output")) + fs.writeFileSync(option("--output"), JSON.stringify(report, null, 2) + "\n"); +// Keep the observable result alive through the timed loops. +if (!sink) throw new Error("Missing benchmark result"); diff --git a/packages/rescript-relay/benchmarks/fixtures.js b/packages/rescript-relay/benchmarks/fixtures.js new file mode 100644 index 00000000..d21114be --- /dev/null +++ b/packages/rescript-relay/benchmarks/fixtures.js @@ -0,0 +1,119 @@ +// Plain fixtures keep this benchmark independent of compilation and React. +const rows = Array.from({ length: 100 }, (_, i) => ({ + id: String(i), + name: "User " + i, + status: i % 2 ? "ONLINE" : "OFFLINE", + avatar: null, + profile: { bio: null, score: i }, +})); +const converters = { + enum: (v) => v.toLowerCase(), + scalar: (v) => new Date(v), + union: (v) => v, +}; +const cases = [ + { + name: "small fragment", + root: rows[0], + maps: { __root: { "": { f: "" }, status: { e: "enum" } } }, + }, + { + name: "unchanged object", + root: { id: "1", name: "User", profile: { score: 42 } }, + maps: {}, + }, + { + name: "nullable query", + root: { viewer: rows[0], missing: null }, + maps: {}, + }, + { + name: "connection / 100 rows", + root: { users: { edges: rows.map((node) => ({ cursor: node.id, node })) } }, + maps: { + __root: { + users_edges_node: { f: "" }, + users_edges_node_status: { e: "enum" }, + }, + }, + }, + { + name: "plural fragment / 100 rows", + root: rows, + maps: { __root: { "": { f: "" }, status: { e: "enum" } } }, + }, + { + name: "union list / 100 rows", + root: { members: rows.map((v) => ({ ...v, __typename: "User" })) }, + maps: { + __root: { + members: { u: "union" }, + members_User: { f: "" }, + members_User_status: { e: "enum" }, + }, + }, + }, + { + name: "custom scalar list", + root: { dates: Array(100).fill("2025-01-01T00:00:00Z"), after: null }, + maps: { __root: { dates: { ca: "scalar" } } }, + }, + { + name: "opaque JSON list", + root: { items: rows }, + maps: { __root: { items: { b: "a" } } }, + }, + { + name: "recursive inputs", + root: { input: { status: "ONLINE", children: rows } }, + maps: { + __root: { input: { r: "Input" } }, + Input: { status: { e: "enum" }, children: { r: "Input" } }, + }, + nullable: null, + }, +]; +module.exports = { cases, converters }; + +// Expected data is independent of the instruction interpreter. Fragment refs are +// checked separately in unit/mounted tests (older releases rewrote nested refs). +const convertedRow = (row, nullable, enumValue) => ({ + ...row, + avatar: nullable, + status: enumValue ? row.status.toLowerCase() : row.status, + profile: { ...row.profile, bio: nullable }, +}); +const expected = [ + convertedRow(rows[0], undefined, true), + cases[1].root, + { viewer: convertedRow(rows[0], undefined, false), missing: undefined }, + { + users: { + edges: rows.map((row) => ({ + cursor: row.id, + node: convertedRow(row, undefined, true), + })), + }, + }, + rows.map((row) => convertedRow(row, undefined, true)), + { + members: rows.map((row) => ({ + ...convertedRow(row, undefined, true), + __typename: "User", + })), + }, + { + dates: Array.from({ length: 100 }, () => new Date("2025-01-01T00:00:00Z")), + after: undefined, + }, + { items: rows }, + { + input: { + status: "online", + children: rows.map((row) => convertedRow(row, null, true)), + }, + }, +]; +cases.forEach((fixture, i) => { + fixture.expected = expected[i]; +}); diff --git a/packages/rescript-relay/benchmarks/results/README.md b/packages/rescript-relay/benchmarks/results/README.md new file mode 100644 index 00000000..eb733a39 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/README.md @@ -0,0 +1,27 @@ +# Recorded local comparison + +Baseline: `520cac4933c118a85cf0dffcd1a19a5dba34ad4f` (latest default branch when work began). +Candidate: the accompanying `src/utils.js` changes. Recorded 2026-09-21. + +Both runs used v24.16.0, linux x64, AMD RYZEN AI MAX+ 395 w/ Radeon 8060S, 15 samples per case, +with a 40 ms calibration target. These runs were sequential, candidate +first, and reproduced the earlier baseline-first comparison. Times vary by +runtime and machine; these are local microbenchmark results, not guarantees. + +| Case | Baseline median | Optimized median | Speedup | New output objects (before → after) | +|---|---:|---:|---:|---:| +| small fragment | 1.39 µs | 0.26 µs | 5.36× | 3 → 3 | +| unchanged object | 0.79 µs | 0.11 µs | 7.35× | 1 → 0 | +| nullable query | 2.15 µs | 0.43 µs | 5.03× | 3 → 3 | +| connection / 100 rows | 787.34 µs | 67.43 µs | 11.68× | 703 → 403 | +| plural fragment / 100 rows | 141.25 µs | 30.76 µs | 4.59× | 301 → 301 | +| union list / 100 rows | 229.87 µs | 62.56 µs | 3.67× | 302 → 302 | +| custom scalar list | 12.47 µs | 11.25 µs | 1.11× | 102 → 102 | +| opaque JSON list | 0.60 µs | 0.35 µs | 1.72× | 2 → 0 | +| recursive inputs | 359.82 µs | 30.62 µs | 11.75× | 203 → 103 | + +Raw reports include p10/p90 spreads. See [benchmark instructions](../README.md) +for reproduction and the limits of the output-object count. Date construction +dominates the custom-scalar list case; its small timing difference is within the +observed noise. CPU profiling confirmed traversal, field dispatch, fragment +snapshot copying, and scalar callbacks as the remaining work. diff --git a/packages/rescript-relay/benchmarks/results/baseline.json b/packages/rescript-relay/benchmarks/results/baseline.json new file mode 100644 index 00000000..724e5fbc --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/baseline.json @@ -0,0 +1,94 @@ +{ + "fixtureVersion": 1, + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "baseline src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 51200, + "newOutputObjects": 3, + "medianNs": 1385.9065429687512, + "p10Ns": 1287.5365039062503, + "p90Ns": 1633.2075390625, + "opsPerSecond": 721549.3750811649 + }, + { + "name": "unchanged object", + "iterations": 51200, + "newOutputObjects": 1, + "medianNs": 786.9883593750026, + "p10Ns": 746.9491992187471, + "p90Ns": 873.8155468750009, + "opsPerSecond": 1270666.8251029323 + }, + { + "name": "nullable query", + "iterations": 25600, + "newOutputObjects": 3, + "medianNs": 2151.13203125, + "p10Ns": 2052.9993359375, + "p90Ns": 2333.326679687495, + "opsPerSecond": 464871.51205633365 + }, + { + "name": "connection / 100 rows", + "iterations": 100, + "newOutputObjects": 703, + "medianNs": 787343.75, + "p10Ns": 757014.3700000016, + "p90Ns": 847085.5799999981, + "opsPerSecond": 1270.0932724746974 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 400, + "newOutputObjects": 301, + "medianNs": 141254.90249999985, + "p10Ns": 136209.04000000108, + "p90Ns": 151119.6025000004, + "opsPerSecond": 7079.4003061238955 + }, + { + "name": "union list / 100 rows", + "iterations": 200, + "newOutputObjects": 302, + "medianNs": 229873.82499999966, + "p10Ns": 222922.87500000384, + "p90Ns": 255679.87999999788, + "opsPerSecond": 4350.212556823299 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "medianNs": 12473.766562499974, + "p10Ns": 11483.63421875004, + "p90Ns": 13477.948750000054, + "opsPerSecond": 80168.24709597431 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 2, + "medianNs": 600.0888574218699, + "p10Ns": 566.5839941406325, + "p90Ns": 647.8469628906237, + "opsPerSecond": 1666419.8770432887 + }, + { + "name": "recursive inputs", + "iterations": 100, + "newOutputObjects": 203, + "medianNs": 359820.4699999951, + "p10Ns": 337718.6000000074, + "p90Ns": 382805.19999998435, + "opsPerSecond": 2779.163731290812 + } + ], + "baseRevision": "520cac4933c118a85cf0dffcd1a19a5dba34ad4f", + "recordedDate": "2026-09-21" +} diff --git a/packages/rescript-relay/benchmarks/results/optimized.json b/packages/rescript-relay/benchmarks/results/optimized.json new file mode 100644 index 00000000..e770a1e1 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/optimized.json @@ -0,0 +1,94 @@ +{ + "fixtureVersion": 1, + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "working-tree src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "medianNs": 258.71845703125007, + "p10Ns": 243.4020849609375, + "p90Ns": 286.2405078124999, + "opsPerSecond": 3865205.488138838 + }, + { + "name": "unchanged object", + "iterations": 409600, + "newOutputObjects": 0, + "medianNs": 107.08943603515652, + "p10Ns": 102.9204467773437, + "p90Ns": 121.46514648437524, + "opsPerSecond": 9337989.226796458 + }, + { + "name": "nullable query", + "iterations": 102400, + "newOutputObjects": 3, + "medianNs": 427.823339843747, + "p10Ns": 385.3941406249994, + "p90Ns": 486.95416015624994, + "opsPerSecond": 2337413.382741642 + }, + { + "name": "connection / 100 rows", + "iterations": 800, + "newOutputObjects": 403, + "medianNs": 67429.24499999959, + "p10Ns": 64157.26374999963, + "p90Ns": 73941.97374999976, + "opsPerSecond": 14830.360328074355 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 1600, + "newOutputObjects": 301, + "medianNs": 30763.08374999996, + "p10Ns": 27986.07250000003, + "p90Ns": 35886.9681249999, + "opsPerSecond": 32506.494086438954 + }, + { + "name": "union list / 100 rows", + "iterations": 800, + "newOutputObjects": 302, + "medianNs": 62561.63125000058, + "p10Ns": 57967.87124999924, + "p90Ns": 68423.35625000033, + "opsPerSecond": 15984.237942964295 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "medianNs": 11251.709062500198, + "p10Ns": 10571.279374999845, + "p90Ns": 12130.349999999908, + "opsPerSecond": 88875.38723630967 + }, + { + "name": "opaque JSON list", + "iterations": 204800, + "newOutputObjects": 0, + "medianNs": 349.4462451171865, + "p10Ns": 341.903315429688, + "p90Ns": 368.32323730468636, + "opsPerSecond": 2861670.4685570477 + }, + { + "name": "recursive inputs", + "iterations": 1600, + "newOutputObjects": 103, + "medianNs": 30618.235625000238, + "p10Ns": 27549.50000000008, + "p90Ns": 34586.33500000019, + "opsPerSecond": 32660.27514607946 + } + ], + "baseRevision": "520cac4933c118a85cf0dffcd1a19a5dba34ad4f", + "recordedDate": "2026-09-21" +} diff --git a/packages/rescript-relay/jest.conversion.config.js b/packages/rescript-relay/jest.conversion.config.js new file mode 100644 index 00000000..43a91cbd --- /dev/null +++ b/packages/rescript-relay/jest.conversion.config.js @@ -0,0 +1,18 @@ +const config = require("./jest.config"); +module.exports = { + ...config, + bail: false, + testRegex: "/__tests__/utils.*-tests.js$", + roots: ["/__tests__"], + collectCoverage: true, + collectCoverageFrom: ["src/utils.js"], + coverageDirectory: "/coverage/conversion", + coverageThreshold: { + "./src/utils.js": { + branches: 95, + functions: 100, + lines: 100, + statements: 98, + }, + }, +}; diff --git a/packages/rescript-relay/package.json b/packages/rescript-relay/package.json index ac5a4a8c..8582dd2a 100644 --- a/packages/rescript-relay/package.json +++ b/packages/rescript-relay/package.json @@ -36,7 +36,10 @@ "build:test": "./build-compiler-dev.sh && ./rescript-relay-compiler && ENABLE_PERSISTING=true ./rescript-relay-compiler && rm ./__tests_preloaded__/__generated__/RelaySchemaAssets_graphql.res", "postinstall": "node postinstall.js", "test": "jest", - "test:ci": "jest --ci --runInBand" + "test:ci": "jest --ci --runInBand", + "test:conversion": "jest --config jest.conversion.config.js --runInBand", + "test:all": "yarn build && yarn test:ci && ENABLE_PERSISTING=true yarn test:ci && yarn test:conversion", + "bench:conversion": "node benchmarks/conversion.js" }, "devDependencies": { "@glennsl/rescript-fetch": "^0.2.0", diff --git a/packages/rescript-relay/src/utils.js b/packages/rescript-relay/src/utils.js index f1b6c687..645b7ab8 100644 --- a/packages/rescript-relay/src/utils.js +++ b/packages/rescript-relay/src/utils.js @@ -1,61 +1,33 @@ -function getNewObj(maybeNewObj, currentObj) { - return maybeNewObj || Object.assign({}, currentObj); -} - -function getPathName(path) { - return path.join("_"); -} - -function makeNewPath(currentPath, newKeys) { - return [].concat(currentPath, newKeys); -} - -function getTypename(v) { - if (v != null && typeof v === "object" && v.__typename != null) { - return v.__typename; - } -} +// Shared read-only fallback: avoid allocating an empty map for every field. +var empty = Object.freeze({}); function unwrapInputUnion(obj) { if (obj != null && typeof obj === "object" && "__$inputUnion" in obj) { - return { - [obj["__$inputUnion"]]: obj["_0"], - }; + return { [obj["__$inputUnion"]]: obj._0 }; } - return obj; } -/** - * Runs on each object in the tree and follows the provided instructions - * to apply transforms etc. - */ +function withFragmentRefs(obj) { + var result = Object.assign({}, obj); + // Both refs describe the original Relay snapshot, before conversions. + result.fragmentRefs = Object.assign({}, obj); + result.updatableFragmentRefs = result.fragmentRefs; + return result; +} + function traverse( - fullInstructionMap, - currentPath, - currentObj, - instructionMap, + maps, + prefix, + obj, + instructions, converters, - nullableValue, - instructionPaths, - addFragmentOnRoot + nullable, + fragment, ) { - // We lazily set up a new object for each "level", as we don't want to mutate - // what comes back from the Relay store, and nor do we want to create new - // objects unless we need to. And we only need to when we need to change - // something. - var newObj; - - if (addFragmentOnRoot) { - newObj = getNewObj(newObj, currentObj); - newObj.fragmentRefs = Object.assign({}, newObj); - newObj.updatableFragmentRefs = newObj.fragmentRefs; - } - - for (var key in currentObj) { - // Ensure we don't move into internal properties coming from Relay, with the - // exception of the few names allowed to start with double underscores - // ("__typename" and "__id"), and any Relay provided variables. + var result = fragment ? withFragmentRefs(obj) : undefined; + for (var key in obj) { + // Relay metadata may contain cycles and must remain opaque. if ( key.startsWith("__") && key !== "__typename" && @@ -64,361 +36,224 @@ function traverse( ) continue; - var isUnion = false; - var originalValue = currentObj[key]; - - // Instructions are stored by the path in the object where they apply - var thisPath = makeNewPath(currentPath, [key]); - var path = getPathName(thisPath); - - var instructions = instructionMap[path] || {}; - - if (currentObj[key] == null) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = nullableValue; - continue; - } - - if (currentObj[key] && currentObj[key].BS_PRIVATE_NESTED_SOME_NONE >= 0) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = currentObj[key]; - continue; - } - - var shouldConvertRootObj = - typeof instructions["r"] === "string" && - fullInstructionMap[instructions["r"]]; - - var shouldAddFragmentFn = instructions["f"] === ""; - - var shouldConvertEnum = - typeof instructions["e"] === "string" && !!converters[instructions["e"]]; - - // This is true for non-arrays that are to be converted - var shouldConvertCustomField = - typeof instructions["c"] === "string" && !!converters[instructions["c"]]; - - // This is true for arrays that are to be converted. This and the above - // won't be true at the same time. - var shouldConvertCustomFieldArray = - typeof instructions["ca"] === "string" && - !!converters[instructions["ca"]]; - - // Special case when this is a custom field that's an array. Ensures we - // don't accidentally move into the array when we're not supposed to. - if (shouldConvertCustomFieldArray && Array.isArray(currentObj[key])) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = currentObj[key].map(converters[instructions["ca"]]); - continue; - } - - var shouldBlockTraversal = typeof instructions["b"] === "string"; - var allowGoingIntoArray = shouldBlockTraversal - ? instructions["b"] === "a" - : true; - - if (shouldBlockTraversal && !allowGoingIntoArray) { - newObj = getNewObj(newObj, currentObj); + var value = obj[key]; + var converted; + if (value == null) { + converted = nullable; + } else if (value.BS_PRIVATE_NESTED_SOME_NONE >= 0) { continue; + } else { + // Carry the encoded prefix rather than allocating and joining path arrays. + var path = prefix + key; + var instruction = instructions[path]; + // Most selected scalar fields need no conversion. + if (instruction === undefined && typeof value !== "object") continue; + instruction = instruction || empty; + converted = convertField( + value, + instruction, + maps, + path, + instructions, + converters, + nullable, + ); } - - var shouldConvertUnion = - typeof instructions["u"] === "string" && !!converters[instructions["u"]]; - - /** - * Handle arrays - */ - - // Special case when this is a custom field that's an array. Ensures we - // don't accidentally move into the array when we're not supposed to. - if (shouldConvertCustomField && Array.isArray(currentObj[key])) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = converters[instructions["c"]](originalValue); - continue; + if (converted !== value) { + if (result === undefined) result = Object.assign({}, obj); + result[key] = converted; } + } + return result === undefined ? obj : result; +} - if (Array.isArray(currentObj[key])) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = currentObj[key].map(function (v) { - if (v == null) { - return nullableValue; - } - if (shouldConvertRootObj) { - return traverser( - unwrapInputUnion(v), - fullInstructionMap, - converters, - nullableValue, - instructions["r"] - ); - } - - if (shouldConvertEnum) { - return converters[instructions["e"]](v); - } - - if (shouldConvertCustomField) { - return converters[instructions["c"]](v); - } - - if (shouldConvertUnion && v != null && typeof v === "object") { - var typename = getTypename(v); - - if (typename != null) { - isUnion = true; - var unionObj = v; - - // Means we're wrapping, and this will be a ReScript value. - if (nullableValue === null) { - // Convert it back to a flat JS value - unionObj = converters[instructions["u"]](v); - } - - var newPath = makeNewPath(currentPath, [key, typename]); - - var unionRootHasFragment = - (instructionMap[getPathName(newPath)] || {}).f === ""; - - var traversedValue = traverse( - fullInstructionMap, - newPath, - unionObj, - instructionMap, - converters, - nullableValue, - instructionPaths, - unionRootHasFragment - ); - - // Undefined means we're going from JS to ReScript, in which case we - // need to run the conversion here rather than earlier. - return nullableValue === undefined - ? converters[instructions["u"]](traversedValue) - : traversedValue; - } - } - - if (shouldAddFragmentFn && typeof v === "object" && !Array.isArray(v)) { - var objWithFragmentFn = Object.assign({}, v); - objWithFragmentFn.fragmentRefs = Object.assign({}, objWithFragmentFn); - objWithFragmentFn.updatableFragmentRefs = - objWithFragmentFn.fragmentRefs; - return objWithFragmentFn; - } - - return v; - }); - } else { - /** - * Handle normal values. - */ - var v = currentObj[key]; +function convertUnion( + value, + convert, + maps, + path, + instructions, + converters, + nullable, +) { + var unionPath = path + "_" + value.__typename; + var fragment = (instructions[unionPath] || empty).f === ""; + var raw = nullable === null ? convert(value) : value; + var result = traverse( + maps, + unionPath + "_", + raw, + instructions, + converters, + nullable, + fragment, + ); + return nullable === undefined ? convert(result) : result; +} - if (shouldConvertRootObj) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = traverser( - unwrapInputUnion(v), - fullInstructionMap, +function convertField( + value, + instruction, + maps, + path, + instructions, + converters, + nullable, +) { + var isArray = Array.isArray(value); + var customArray = + typeof instruction.ca === "string" && converters[instruction.ca]; + if (isArray && customArray) { + // Preserve Array.map's converter calling convention, including null elements. + return value.map(customArray); + } + var blocked = typeof instruction.b === "string"; + if (blocked && instruction.b !== "a") return value; + + var custom = typeof instruction.c === "string" && converters[instruction.c]; + // A scalar can itself be represented by an array. Its result is always opaque. + if (isArray && custom) return custom(value); + + var root = typeof instruction.r === "string" && maps[instruction.r]; + var enumConverter = + typeof instruction.e === "string" && converters[instruction.e]; + var union = typeof instruction.u === "string" && converters[instruction.u]; + var fragment = instruction.f === ""; + + if (isArray) { + var result; + for (var i = 0; i < value.length; i++) { + // Match map's handling of sparse arrays. + if (!(i in value)) continue; + var item = value[i]; + var converted = item; + if (item == null) { + converted = nullable; + } else if (root) { + converted = traverser( + unwrapInputUnion(item), + maps, converters, - nullableValue, - instructions["r"] + nullable, + instruction.r, ); - continue; - } - - if (shouldConvertEnum) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = converters[instructions["e"]](v); - } - - if (shouldConvertCustomField) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = converters[instructions["c"]](v); - // Ensure that the custom scalar value itself isn't traversed more. - continue; - } - - if (shouldConvertUnion && v != null && typeof v === "object") { - var typename = getTypename(v); - - if (typename != null) { - isUnion = true; - var unionObj = v; - - // Means we're wrapping, and this will be a ReScript value. - if (nullableValue === null) { - // Convert it back to a flat JS value - unionObj = converters[instructions["u"]](v); - } - - var newPath = makeNewPath(currentPath, [key, typename]); - - var unionRootHasFragment = - (instructionMap[getPathName(newPath)] || {}).f === ""; - - var traversedValue = traverse( - fullInstructionMap, - newPath, - unionObj, - instructionMap, - converters, - nullableValue, - instructionPaths, - unionRootHasFragment - ); - - newObj = getNewObj(newObj, currentObj); - - newObj[key] = - // Undefined means we're going from JS to ReScript, in which case we - // need to run the conversion here rather than earlier. - nullableValue === undefined - ? converters[instructions["u"]](traversedValue) - : traversedValue; - } - } - - if (shouldAddFragmentFn && typeof v === "object" && !Array.isArray(v)) { - newObj = getNewObj(newObj, currentObj); - var objWithFragmentFn = Object.assign({}, v); - objWithFragmentFn.fragmentRefs = Object.assign({}, objWithFragmentFn); - objWithFragmentFn.updatableFragmentRefs = - objWithFragmentFn.fragmentRefs; - - newObj[key] = objWithFragmentFn; - } - } - - if (originalValue != null && !isUnion) { - var nextObj = (newObj && newObj[key]) || currentObj[key]; - - if (typeof nextObj === "object" && !Array.isArray(originalValue)) { - var traversedObj = traverse( - fullInstructionMap, - thisPath, - nextObj, - instructionMap, + } else if (enumConverter) { + converted = enumConverter(item); + } else if (union && typeof item === "object" && item.__typename != null) { + converted = convertUnion( + item, + union, + maps, + path, + instructions, converters, - nullableValue, - instructionPaths + nullable, ); - - if (traversedObj !== nextObj) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = traversedObj; - } - } else if (Array.isArray(originalValue) && !shouldBlockTraversal) { - newObj = getNewObj(newObj, currentObj); - newObj[key] = nextObj.map(function (o) { - if (typeof o === "object" && o != null && !Array.isArray(o)) { - return traverse( - fullInstructionMap, - thisPath, - o, - instructionMap, + } else if (typeof item === "object" && !Array.isArray(item)) { + converted = blocked + ? fragment + ? withFragmentRefs(item) + : item + : traverse( + maps, + path + "_", + item, + instructions, converters, - nullableValue, - instructionPaths + nullable, + fragment, ); - } else if (o == null) { - return nullableValue; - } else { - return o; - } - }); + } + if (converted !== item) { + if (result === undefined) result = value.slice(); + result[i] = converted; } } + return result === undefined ? value : result; } - return newObj || currentObj; + if (root) + return traverser( + unwrapInputUnion(value), + maps, + converters, + nullable, + instruction.r, + ); + if (custom) return custom(value); + if (enumConverter) return enumConverter(value); + if (typeof value === "object") { + if (union && value.__typename != null) { + return convertUnion( + value, + union, + maps, + path, + instructions, + converters, + nullable, + ); + } + return traverse( + maps, + path + "_", + value, + instructions, + converters, + nullable, + fragment, + ); + } + return value; } /** - * This function takes an object (snapshot from the Relay store) and applies a - * set of conversions deeply on the object (instructions coming from "converters"-prop). - * It converts nullable values either to null or undefined, and it wraps/unwraps enums - * and unions. - * - * It preserves structural integrity where possible, and return new objects where properties - * have been modified. + * Convert Relay snapshots (nullable=undefined) or write payloads (nullable=null). + * Instructions and converters are read on each call; neither they nor payloads + * are cached or mutated. Unchanged branches retain their original identity. */ -function traverser( - root, - instructionMaps_, - theConverters, - nullableValue, - rootObjectKey -) { - if (!root) { - return nullableValue; +function traverser(root, instructionMaps, converters, nullable, rootObjectKey) { + if (!root) return nullable; + var maps = instructionMaps || empty; + var instructions = maps[rootObjectKey || "__root"] || empty; + converters = converters || empty; + var rootInstruction = instructions[""] || empty; + var union = converters[rootInstruction.u]; + var fragment = rootInstruction.f === ""; + + function convertRoot(value) { + if (value == null) return nullable; + var prefix = ""; + var hasFragment = fragment; + if (union != null) { + prefix = value.__typename + "_"; + hasFragment = (instructions[value.__typename] || empty).f === ""; + } + var result = traverse( + maps, + prefix, + value, + instructions, + converters, + nullable, + hasFragment, + ); + return union != null ? union(result) : result; } - var instructionMaps = instructionMaps_ || {}; - var instructionMap = instructionMaps[rootObjectKey || "__root"] || {}; - - var converters = theConverters == null ? {} : theConverters; - var instructionPaths = Object.keys(instructionMap); - - // We'll add the fragmentRefs reference to the root if needed here. - var fragmentsOnRoot = (instructionMap[""] || {}).f === ""; - var unionRootConverter = converters[(instructionMap[""] || {}).u]; - if (Array.isArray(root)) { - return root.map(function (v) { - if (v == null) { - return nullableValue; - } - - var n = []; - - // Since a root level union is treated as a "new root level", we'll need - // to do a separate check here of whether there's a fragment on the root - // we need to account for, or not. - if (unionRootConverter != null) { - n = [v.__typename]; - fragmentsOnRoot = (instructionMap[v.__typename] || {}).f === ""; + var result; + for (var i = 0; i < root.length; i++) { + if (!(i in root)) continue; + var converted = convertRoot(root[i]); + if (converted !== root[i]) { + if (result === undefined) result = root.slice(); + result[i] = converted; } - - var traversedObj = traverse( - instructionMaps, - n, - v, - instructionMap, - converters, - nullableValue, - instructionPaths, - fragmentsOnRoot - ); - - return unionRootConverter != null - ? unionRootConverter(traversedObj) - : traversedObj; - }); - } - - var newObj = Object.assign({}, root); - - var n = []; - - // Same as in the union array check above - if there's a fragment in the new - // root created by the union, we need to account for that separately here. - if (unionRootConverter != null) { - n = [newObj.__typename]; - fragmentsOnRoot = (instructionMap[newObj.__typename] || {}).f === ""; + } + return result === undefined ? root : result; } - - var v = traverse( - instructionMaps, - n, - newObj, - instructionMap, - converters, - nullableValue, - instructionPaths, - fragmentsOnRoot - ); - - return unionRootConverter != null ? unionRootConverter(v) : v; + return convertRoot(root); } module.exports = { traverser }; From 883d7d4c093b931a4f57eadb4b3fb66742456d9d Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 21 Sep 2026 21:32:17 +0200 Subject: [PATCH 02/23] Audit conversion semantics and compare string-path optimization --- .../__tests__/utils-path-tests.js | 171 ++++++++++++++++++ .../benchmarks/results/pr-673.json | 92 ++++++++++ .../docs/conversion-contract.md | 100 ++++++++++ 3 files changed, 363 insertions(+) create mode 100644 packages/rescript-relay/__tests__/utils-path-tests.js create mode 100644 packages/rescript-relay/benchmarks/results/pr-673.json create mode 100644 packages/rescript-relay/docs/conversion-contract.md diff --git a/packages/rescript-relay/__tests__/utils-path-tests.js b/packages/rescript-relay/__tests__/utils-path-tests.js new file mode 100644 index 00000000..82bda2f6 --- /dev/null +++ b/packages/rescript-relay/__tests__/utils-path-tests.js @@ -0,0 +1,171 @@ +const { traverser } = require("../src/utils"); + +describe("conversion instruction paths", () => { + test("handles nested underscore paths, nullability, enums, scalars, arrays, and fragments without mutating input", () => { + const input = { + account_details: { + status_level: "2", + optional_label: null, + scores: ["3", null], + profile_data: { + created_at: "4", + }, + }, + }; + const originalInput = JSON.parse(JSON.stringify(input)); + + const result = traverser( + input, + { + __root: { + "": { f: "" }, + account_details: { f: "" }, + account_details_status_level: { e: "Status" }, + account_details_optional_label: { n: "" }, + account_details_scores: { n: "", e: "Status" }, + account_details_profile_data: { f: "" }, + account_details_profile_data_created_at: { c: "Int" }, + }, + }, + { + Status: (value) => Number(value), + Int: (value) => Number(value), + }, + undefined + ); + + expect(result).toEqual({ + fragmentRefs: expect.any(Object), + updatableFragmentRefs: expect.any(Object), + account_details: { + fragmentRefs: expect.any(Object), + updatableFragmentRefs: expect.any(Object), + status_level: 2, + optional_label: undefined, + scores: [3, undefined], + profile_data: { + fragmentRefs: expect.any(Object), + updatableFragmentRefs: expect.any(Object), + created_at: 4, + }, + }, + }); + expect(input).toEqual(originalInput); + }); + + test("handles nested unions and root unions for objects and arrays", () => { + const converters = { + Node: (value) => ({ kind: value.__typename, value }), + Status: (value) => Number(value), + }; + const nestedInput = { + nodes: [ + null, + { __typename: "User", status_code: "5" }, + { __typename: "Team", status_code: "6" }, + ], + }; + const nestedOriginal = JSON.parse(JSON.stringify(nestedInput)); + const instructions = { + __root: { + nodes: { n: "", u: "Node" }, + nodes_User: { f: "" }, + nodes_User_status_code: { e: "Status" }, + nodes_Team_status_code: { e: "Status" }, + }, + }; + + expect( + traverser( + nestedInput, + instructions, + converters, + undefined + ) + ).toEqual({ + nodes: [ + undefined, + { + kind: "User", + value: { + fragmentRefs: expect.any(Object), + updatableFragmentRefs: expect.any(Object), + __typename: "User", + status_code: 5, + }, + }, + { + kind: "Team", + value: { __typename: "Team", status_code: 6 }, + }, + ], + }); + expect(nestedInput).toEqual(nestedOriginal); + + const rootInstructions = { + __root: { + "": { u: "Node" }, + User: { f: "" }, + User_status_code: { e: "Status" }, + }, + }; + const user = { __typename: "User", status_code: "7" }; + + expect( + traverser(user, rootInstructions, converters, undefined) + ).toEqual({ + kind: "User", + value: { + fragmentRefs: expect.any(Object), + updatableFragmentRefs: expect.any(Object), + __typename: "User", + status_code: 7, + }, + }); + expect( + traverser([user, null], rootInstructions, converters, undefined) + ).toEqual([ + { + kind: "User", + value: { + fragmentRefs: expect.any(Object), + updatableFragmentRefs: expect.any(Object), + __typename: "User", + status_code: 7, + }, + }, + undefined, + ]); + expect(user).toEqual({ __typename: "User", status_code: "7" }); + }); + + test("uses the selected root object instruction map", () => { + const input = { + filter_value: { + minimum_score: "8", + optional_score: null, + }, + }; + + expect( + traverser( + input, + { + Variables: { filter_value: { r: "FilterInput" } }, + FilterInput: { + minimum_score: { c: "Int" }, + optional_score: { n: "" }, + }, + }, + { Int: (value) => Number(value) }, + undefined, + "Variables" + ) + ).toEqual({ + filter_value: { minimum_score: 8, optional_score: undefined }, + }); + expect(input).toEqual({ + filter_value: { minimum_score: "8", optional_score: null }, + }); + }); +}); diff --git a/packages/rescript-relay/benchmarks/results/pr-673.json b/packages/rescript-relay/benchmarks/results/pr-673.json new file mode 100644 index 00000000..c2674a29 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/pr-673.json @@ -0,0 +1,92 @@ +{ + "fixtureVersion": 1, + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "/tmp/relay-conversion-audit/pr-673-utils.cjs", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "medianNs": 342.3455322265623, + "p10Ns": 325.91325683593766, + "p90Ns": 418.4350732421876, + "opsPerSecond": 2921025.413990815 + }, + { + "name": "unchanged object", + "iterations": 204800, + "newOutputObjects": 1, + "medianNs": 202.29527343750055, + "p10Ns": 194.57396484375056, + "p90Ns": 214.54651367187606, + "opsPerSecond": 4943269.227241494 + }, + { + "name": "nullable query", + "iterations": 102400, + "newOutputObjects": 3, + "medianNs": 625.883134765628, + "p10Ns": 605.5560156250017, + "p90Ns": 674.15791015625, + "opsPerSecond": 1597742.3650734192 + }, + { + "name": "connection / 100 rows", + "iterations": 200, + "newOutputObjects": 703, + "medianNs": 267561.3300000009, + "p10Ns": 252490.7950000011, + "p90Ns": 314063.4150000005, + "opsPerSecond": 3737.4608655144475 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 1600, + "newOutputObjects": 301, + "medianNs": 38205.29124999951, + "p10Ns": 36911.118125000256, + "p90Ns": 41716.802500000085, + "opsPerSecond": 26174.38494203373 + }, + { + "name": "union list / 100 rows", + "iterations": 800, + "newOutputObjects": 302, + "medianNs": 77325.44500000018, + "p10Ns": 75914.19500000028, + "p90Ns": 84684.0025000006, + "opsPerSecond": 12932.353638572627 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "medianNs": 10719.061718749997, + "p10Ns": 10580.89640624999, + "p90Ns": 11061.570468749976, + "opsPerSecond": 93291.74756506718 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 2, + "medianNs": 419.1014160156303, + "p10Ns": 397.51949218749695, + "p90Ns": 480.5745214843782, + "opsPerSecond": 2386057.3164055003 + }, + { + "name": "recursive inputs", + "iterations": 400, + "newOutputObjects": 203, + "medianNs": 117512.12249999752, + "p10Ns": 116141.18750000215, + "p90Ns": 126153.6524999974, + "opsPerSecond": 8509.760344087234 + } + ] +} diff --git a/packages/rescript-relay/docs/conversion-contract.md b/packages/rescript-relay/docs/conversion-contract.md new file mode 100644 index 00000000..97fa5ca1 --- /dev/null +++ b/packages/rescript-relay/docs/conversion-contract.md @@ -0,0 +1,100 @@ +# Conversion contract and audit + +Coverage is not proof of correctness. This document distinguishes the intended +contract from historical behavior and limits of the input protocol. Tests must +assert the contract independently of the optimized implementation. + +## Sources and scope + +The audited compiler is submodule `ef6d68326a6661887a2a09fd12028f201e32d78f`: +`relay-typegen/src/rescript_ast.rs` (`ConverterInstructions`), `rescript.rs` +(`ast_to_prop_value`, `write_internal_assets`), and `rescript_utils.rs` +(`instruction_to_key_value_pair`). All checked-in generated artifacts were also +inspected. Current compiler opcodes are `c`, `ca`, `r`, `u`, `f`, and `b`; +`e` is retained for older artifacts. Nullable conversion happens implicitly, +regardless of historical `n`/`na` hints. Response/fragment conversion, variables, +provided variables, mutation/raw responses, and persisted queries use this API. + +[PR #673](https://github.com/zth/rescript-relay/pull/673) independently replaces +path arrays with strings. Its regression cases are retained here, and its +implementation is included in the benchmark comparisons. Its reported real-app +measurements are separate evidence, not our local microbenchmark results. + +## Supported data + +- Plain, own enumerable string-keyed data records and arrays, including sparse + arrays, null-prototype records, frozen inputs, and shared subtrees. +- Null and undefined normalize to the requested nullable sentinel. Missing + properties remain missing; false, zero, empty strings, and option markers + remain distinct. Converter outputs are opaque even when they are null, + undefined, arrays, class instances, or objects containing nulls. +- Relay metadata beginning `__` is opaque, except `__id`, `__typename`, and + `__relay_internal*` provided variables. Cycles in opaque metadata/scalars/JSON + are allowed. Cycles in traversed GraphQL data, accessors, proxies, symbol-keyed + selections, and invalid primitive roots are outside the GraphQL contract. +- No input, converter-produced object, instruction, or Relay store record may + be mutated. Unchanged branches retain identity. Aliases may share input + objects but conversions are path-specific, not memoized by object identity. +- Converter exceptions propagate unchanged. Siblings are processed in own + property enumeration order and array elements in index order, once each. + No callback-result or snapshot cache is permitted. + +## Intended operations + +| Operation | Semantics | +|---|---| +| Record | Visit fields once, preserving absent fields and opaque metadata. | +| List | Preserve holes; normalize null elements; apply the element plan once. | +| Scalar | Skip absent values/options; invoke callback once; never traverse its result. | +| Opaque JSON | Normalize the field's absence; preserve the entire present value by identity. | +| Fragment refs | Add two properties pointing at the same shallow raw snapshot; never recursively convert this generated snapshot. | +| Union | Select by the original `__typename`; on reads convert members before the union callback; on writes invoke the callback before member conversion. Root and nested unions obey the same order. Unknown types use the generated union callback. | +| Input reference | Unwrap `__$inputUnion` to its selected field, then use the named root's plan. Recursion follows data, not plan construction. | + +A list containing array-valued custom scalars is distinct from a nested GraphQL +list. The protocol must preserve that distinction, not infer it from runtime +array shape. Null elements never reach a custom scalar's parse/serialize function; +they belong to the GraphQL nullable wrapper, not the scalar implementation. + +## Problems found beyond coverage + +1. Two existing tests explicitly blessed `parse(null)` / `serialize(null)` in + scalar lists as "CURRENT BEHAVIOR". They characterized a bug, not the contract. +2. Joining paths with `_` aliases e.g. field `a_b` and nested fields `a.b`. + String paths avoid allocations but cannot resolve this ambiguity. +3. `found_in_array: bool` loses nested list depth. The old `ca`/`b:a` protocol + cannot distinguish nested GraphQL lists from array-valued scalars/JSON. +4. Root union callbacks historically run after traversal in both directions, + unlike nested unions. Identity write callbacks hid the ordering mismatch. +5. Previous fixes addressed repeated traversal of recursive arrays, traversal of + generated fragment snapshots, and one union element affecting its siblings. + +## Redesign boundary + +New artifacts will use a versioned, lossless plan with path segments and explicit +list depth. Plans are prepared once at module initialization into reusable +converters; response conversion does not construct paths or decode opcodes. +Prepared converters snapshot their plan and callback bindings; mutating those +objects afterward is unsupported and must not silently change a prepared plan. +Legacy `traverser` remains available for already-generated artifacts, with its +ambiguous-path/list-depth limitations stated explicitly. New plans reject missing +callbacks/references and conflicting instructions during preparation. + +## Validation layers + +- Explicit shape, ordering, callback count, identity, exception, and nullability + tables, including field-order and instruction-order permutations. +- A simple independent reference evaluator and deterministic generated plans/data; + compare both outputs and callback traces, including round trips where invertible. +- Compiler tests for lossless paths and list depth, plus actual regenerated + artifacts compiled through the PPX/ReScript toolchain. +- Mounted query/fragment/plural/store-update tests, existing mutation/subscription/ + pagination/resolver/catch/updatable tests, and separate persisted-query tests. +- Repeatable targeted mutation tests: each injected fault must cause a behavioral + failure. Coverage thresholds are an additional gate, not the correctness oracle. +- Balanced benchmark comparisons against master, #673, and the first optimized + implementation. Measure preparation separately from warm response conversion. + +No finite suite proves all possible JavaScript behavior. Confidence depends on +this explicit supported contract, independent oracles, real integration tests, +and documented remaining limitations—not a claim of absolute certainty. From f623c592a7391c914483f2dd81fcdc927ef9a014 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 21 Sep 2026 21:42:12 +0200 Subject: [PATCH 03/23] Prepare versioned conversion plans once with independent contract tests --- .../__tests__/helpers/conversionModel.js | 139 +++++ .../__tests__/utils-prepared-tests.js | 547 ++++++++++++++++++ .../rescript-relay/benchmarks/conversion.js | 29 +- .../rescript-relay/benchmarks/fixtures.js | 45 ++ packages/rescript-relay/src/RescriptRelay.res | 5 + .../rescript-relay/src/RescriptRelay.resi | 5 + .../rescript-relay/src/prepareConversion.js | 199 +++++++ packages/rescript-relay/src/utils.js | 5 +- 8 files changed, 963 insertions(+), 11 deletions(-) create mode 100644 packages/rescript-relay/__tests__/helpers/conversionModel.js create mode 100644 packages/rescript-relay/__tests__/utils-prepared-tests.js create mode 100644 packages/rescript-relay/src/prepareConversion.js diff --git a/packages/rescript-relay/__tests__/helpers/conversionModel.js b/packages/rescript-relay/__tests__/helpers/conversionModel.js new file mode 100644 index 00000000..9a5f504b --- /dev/null +++ b/packages/rescript-relay/__tests__/helpers/conversionModel.js @@ -0,0 +1,139 @@ +// Independent, intentionally allocating evaluator over a schema-shaped model. +// It does not use the runtime's path tree, compilation, or copy-on-write logic. +const object = (fields = {}, fragments = false) => ({ + kind: "object", + fields, + fragments, +}); +const list = (item) => ({ kind: "list", item }); +const scalar = (name) => ({ kind: "scalar", name }); +const opaque = { kind: "opaque" }; +const reference = (name) => ({ kind: "reference", name }); +const union = (name, members) => ({ kind: "union", name, members }); +const isMetadata = (key) => + key.startsWith("__") && + key !== "__id" && + key !== "__typename" && + !key.startsWith("__relay_internal"); +const isOption = (v) => + v != null && typeof v === "object" && v.BS_PRIVATE_NESTED_SOME_NONE >= 0; +function unwrap(v) { + return v && Object.hasOwn(v, "__$inputUnion") + ? { [v.__$inputUnion]: v._0 } + : v; +} +function evaluate(schema, value, definitions, converters, nullable) { + if (value == null) return nullable; + if (isOption(value)) return value; + switch (schema.kind) { + case "scalar": + return converters[schema.name](value); + case "opaque": + return value; + case "list": + return value.map((v) => + evaluate(schema.item, v, definitions, converters, nullable), + ); + case "reference": + return evaluate( + definitions[schema.name], + unwrap(value), + definitions, + converters, + nullable, + ); + case "union": { + const member = schema.members[value.__typename] || object(); + const raw = nullable === null ? converters[schema.name](value) : value; + const converted = evaluate( + member, + raw, + definitions, + converters, + nullable, + ); + return nullable === undefined + ? converters[schema.name](converted) + : converted; + } + case "object": { + if (Array.isArray(value)) + return value.map((v) => + evaluate(schema, v, definitions, converters, nullable), + ); + const result = { ...value }; + for (const key of Object.keys(value)) { + if (isMetadata(key)) continue; + const field = schema.fields[key]; + result[key] = field + ? evaluate(field, value[key], definitions, converters, nullable) + : normalize(value[key], nullable); + } + if (schema.fragments) { + result.fragmentRefs = { ...value }; + result.updatableFragmentRefs = result.fragmentRefs; + } + return result; + } + default: + throw new Error("Invalid model kind"); + } +} +function normalize(v, nullable) { + if (v == null) return nullable; + if (isOption(v) || typeof v !== "object") return v; + if (Array.isArray(v)) return v.map((item) => normalize(item, nullable)); + return Object.fromEntries( + Object.keys(v).map((key) => [ + key, + isMetadata(key) ? v[key] : normalize(v[key], nullable), + ]), + ); +} +function encode(definitions) { + const roots = {}; + for (const [name, schema] of Object.entries(definitions)) { + const entries = []; + function visit(node, path) { + const entry = { path }; + let depth = 0; + while (node.kind === "list") { + depth++; + node = node.item; + } + if (depth) entry.list = depth; + if (node.kind === "scalar") entry.scalar = node.name; + if (node.kind === "reference") entry.reference = node.name; + if (node.kind === "opaque") entry.opaque = true; + if (node.kind === "union") entry.union = node.name; + if (node.kind === "object" && node.fragments) entry.fragments = true; + if (Object.keys(entry).length > 1) entries.push(entry); + if (node.kind === "object") + for (const [key, child] of Object.entries(node.fields)) + visit(child, [...path, key]); + if (node.kind === "union") + for (const [key, child] of Object.entries(node.members)) + visit(child, [...path, key]); + } + visit(schema, []); + roots[name] = entries; + } + return { version: 2, roots }; +} +function freeze(v, seen = new Set()) { + if (!v || typeof v !== "object" || seen.has(v)) return v; + seen.add(v); + Object.values(v).forEach((item) => freeze(item, seen)); + return Object.freeze(v); +} +module.exports = { + object, + list, + scalar, + opaque, + reference, + union, + encode, + evaluate, + freeze, +}; diff --git a/packages/rescript-relay/__tests__/utils-prepared-tests.js b/packages/rescript-relay/__tests__/utils-prepared-tests.js new file mode 100644 index 00000000..5f5df7c2 --- /dev/null +++ b/packages/rescript-relay/__tests__/utils-prepared-tests.js @@ -0,0 +1,547 @@ +const { prepareConversion } = require("../src/utils"); +const { + object, + list, + scalar, + opaque, + reference, + union, + encode, + evaluate, + freeze, +} = require("./helpers/conversionModel"); +function prepare(schema, converters = {}, nullable, extra = {}) { + return prepareConversion( + encode({ __root: schema, ...extra }), + converters, + nullable, + ); +} + +describe.each([undefined, null])( + "prepared conversion (nullable=%s)", + (nullable) => { + test("field boundaries cannot collide with underscores or union type names", () => { + const schema = object({ + a_b: scalar("a"), + a: object({ b: scalar("b") }), + members: union("union", { + User_Profile: object({ created_at: scalar("a") }), + }), + }); + const input = freeze({ + a_b: "x", + a: { b: "y" }, + members: { __typename: "User_Profile", created_at: "z" }, + }); + const c = { a: (v) => "a:" + v, b: (v) => "b:" + v, union: (v) => v }; + expect(prepare(schema, c, nullable)(input)).toStrictEqual({ + a_b: "a:x", + a: { b: "b:y" }, + members: { __typename: "User_Profile", created_at: "a:z" }, + }); + }); + + test.each([0, 1, 2, 3])( + "explicit list depth %i preserves array-valued scalar boundaries", + (depth) => { + let schema = scalar("box"); + let wire = "value"; + let expected = ["value"]; + for (let i = 0; i < depth; i++) { + schema = list(schema); + wire = [wire, null, undefined]; + expected = [expected, nullable, nullable]; + } + const box = jest.fn((v) => [v]); + const output = prepare( + object({ value: schema }), + { box }, + nullable, + )(freeze({ value: wire })); + expect(output).toStrictEqual({ value: expected }); + expect(box).toHaveBeenCalledTimes(1); + // The opposite direction can have an array-valued scalar as its input. + const unbox = jest.fn((v) => v[0]); + let boxed = ["value"]; + let unboxed = "value"; + for (let i = 0; i < depth; i++) { + boxed = [boxed, null]; + unboxed = [unboxed, nullable]; + } + expect( + prepare( + object({ value: schema }), + { box: unbox }, + nullable, + )({ value: boxed }), + ).toStrictEqual({ value: unboxed }); + expect(unbox).toHaveBeenCalledTimes(1); + }, + ); + + test("sparse lists, optional markers, missing keys and falsey values stay distinct", () => { + const marker = { BS_PRIVATE_NESTED_SOME_NONE: 0 }; + const input = freeze({ + items: [null, , undefined, marker, 0, false, ""], + marker, + missingSibling: null, + }); + const fn = jest.fn((v) => v); + const output = prepare( + object({ + items: list(scalar("scalar")), + marker: scalar("scalar"), + absent: scalar("scalar"), + }), + { scalar: fn }, + nullable, + )(input); + expect(output.items).toStrictEqual([ + nullable, + , + nullable, + marker, + 0, + false, + "", + ]); + expect(output.marker).toBe(marker); + expect(output).not.toHaveProperty("absent"); + expect(fn.mock.calls).toEqual([[0], [false], [""]]); + }); + + test("nested JSON list depth differs from arrays inside JSON", () => { + const json = freeze([null, { x: null }]); + const input = freeze({ items: [[json, null], null] }); + const output = prepare( + object({ items: list(list(opaque)) }), + {}, + nullable, + )(input); + expect(output.items[0][0]).toBe(json); + expect(output.items[0][1]).toBe(nullable); + expect(output.items[1]).toBe(nullable); + }); + + test("root and nested unions run callbacks in the same order", () => { + for (const nested of [false, true]) { + const schema = union("union", { + User: object({ value: scalar("scalar") }, true), + }); + const calls = []; + const c = { + union: (v) => { + calls.push("union"); + return { ...v, extra: 1 }; + }, + scalar: (v) => { + calls.push("scalar"); + return v + 1; + }, + }; + const input = freeze({ __typename: "User", value: 1 }); + const output = prepare( + nested ? object({ node: schema }) : schema, + c, + nullable, + )(nested ? { node: input } : input); + const node = nested ? output.node : output; + expect(node.value).toBe(2); + expect(node.extra).toBe(1); + expect(calls).toEqual( + nullable === null ? ["union", "scalar"] : ["scalar", "union"], + ); + expect(node.fragmentRefs.value).toBe(1); + expect(node.updatableFragmentRefs).toBe(node.fragmentRefs); + } + }); + + test("unknown union members, nullable members and plural roots are independent", () => { + const schema = union("union", { + User: object({ value: scalar("scalar") }, true), + }); + const c = { + union: (v) => + v.__typename === "User" ? v : { ...v, __typename: "__unselected" }, + scalar: (v) => v + 1, + }; + const input = freeze([ + { __typename: "User", value: 1 }, + null, + { __typename: "Page", value: null }, + ]); + const output = prepare(schema, c, nullable)(input); + expect(output[0].value).toBe(2); + expect(output[1]).toBe(nullable); + expect(output[2]).toStrictEqual({ + __typename: "__unselected", + value: nullable, + }); + expect(output[2]).not.toHaveProperty("fragmentRefs"); + }); + + test("recursive references reset scope and unwrap input unions at every depth", () => { + const definitions = { + Tree: object({ + value: scalar("scalar"), + children: list(reference("Tree")), + }), + Choice: object({ tree: reference("Tree") }), + }; + const scalarFn = jest.fn((v) => Number(v)); + const input = freeze({ + choice: { + __$inputUnion: "tree", + _0: { value: "1", children: [{ value: "2", children: [] }, null] }, + }, + }); + expect( + prepare( + object({ choice: reference("Choice") }), + { scalar: scalarFn }, + nullable, + definitions, + )(input), + ).toStrictEqual({ + choice: { + tree: { value: 1, children: [{ value: 2, children: [] }, nullable] }, + }, + }); + expect(scalarFn.mock.calls).toEqual([["1"], ["2"]]); + }); + + test("shared objects are converted by path, not by identity", () => { + const shared = freeze({ value: "x" }); + const input = freeze({ a: shared, b: shared }); + expect( + prepare( + object({ + a: object({ value: scalar("a") }), + b: object({ value: scalar("b") }), + }), + { a: (v) => "a" + v, b: (v) => "b" + v }, + nullable, + )(input), + ).toStrictEqual({ a: { value: "ax" }, b: { value: "bx" } }); + }); + + test("scalar output and cyclic metadata remain opaque; callbacks can reenter conversion", () => { + const cyclic = {}; + cyclic.self = cyclic; + freeze(cyclic); + let convert; + const c = { + scalar: (v) => + v === "outer" ? convert({ value: "inner", __owner: cyclic }) : cyclic, + }; + convert = prepare(object({ value: scalar("scalar") }), c, nullable); + const output = convert(freeze({ value: "outer", __owner: cyclic })); + expect(output.value.value).toBe(cyclic); + expect(output.__owner).toBe(cyclic); + }); + + test("callbacks follow data property order, independent of instruction order", () => { + const schema = object({ + a: scalar("scalar"), + b: scalar("scalar"), + items: list(scalar("scalar")), + }); + const plan = encode({ __root: schema }); + for (const reverse of [false, true]) { + const c = jest.fn((v) => v + 1); + const entries = plan.roots.__root.slice(); + if (reverse) entries.reverse(); + const convert = prepareConversion( + { version: 2, roots: { __root: entries } }, + { scalar: c }, + nullable, + ); + expect( + convert(freeze({ b: 2, items: [3, null, 4], a: 1 })), + ).toStrictEqual({ b: 3, items: [4, nullable, 5], a: 2 }); + expect(c.mock.calls).toEqual([[2], [3], [4], [1]]); + } + }); + + test("callback errors propagate exactly and stop later siblings without source mutation", () => { + const error = new Error("scalar failure"); + const after = jest.fn((v) => v); + const input = freeze({ before: null, value: "bad", after: "untouched" }); + const convert = prepare( + object({ value: scalar("fail"), after: scalar("after") }), + { + fail: () => { + throw error; + }, + after, + }, + nullable, + ); + expect(() => convert(input)).toThrow(error); + expect(after).not.toHaveBeenCalled(); + expect(input.before).toBeNull(); + }); + }, +); + +test("prepared plans snapshot metadata and callback bindings, but not callback closure state or data", () => { + const plan = encode({ __root: object({ value: scalar("scalar") }) }); + let offset = 1; + const callbacks = { scalar: (v) => v + offset }; + const convert = prepareConversion(plan, callbacks, undefined); + plan.roots.__root.length = 0; + callbacks.scalar = () => 999; + expect(convert({ value: 1 })).toStrictEqual({ value: 2 }); + offset = 2; + expect(convert({ value: 1 })).toStrictEqual({ value: 3 }); +}); + +test("unchanged branches and null-prototype dictionaries preserve data without inherited selections", () => { + const convert = prepare(object()); + const root = freeze({ items: [{ x: 1 }], value: 0 }); + expect(convert(root)).toBe(root); + const raw = Object.assign(Object.create(null), { + constructor: null, + toString: null, + }); + expect(convert(raw)).toEqual({ constructor: undefined, toString: undefined }); + const inherited = Object.create({ hidden: null }); + inherited.value = null; + expect(convert(inherited)).toStrictEqual({ value: undefined }); + const special = JSON.parse('{"__proto__":{"polluted":true},"value":null}'); + const output = convert(special); + expect(Object.getPrototypeOf(output)).toBe(Object.prototype); + expect(Object.hasOwn(output, "__proto__")).toBe(true); + expect({}.polluted).toBeUndefined(); +}); + +describe("prepared plan validation", () => { + test.each([ + [null, {}, undefined, /version 2/], + [{ version: 1, roots: {} }, {}, undefined, /version 2/], + [{ version: 2, roots: {} }, {}, undefined, /Missing conversion root/], + [ + { version: 2, roots: { __root: {} } }, + {}, + undefined, + /Invalid conversion root/, + ], + [ + { version: 2, roots: { __root: [{}] } }, + {}, + undefined, + /Invalid conversion path/, + ], + [ + { version: 2, roots: { __root: [{ path: [1] }] } }, + {}, + undefined, + /Invalid conversion path/, + ], + [ + { version: 2, roots: { __root: [{ path: [], typo: true }] } }, + {}, + undefined, + /Unknown conversion instruction/, + ], + [{ version: 2, roots: { __root: [] } }, {}, false, /nullable sentinel/], + [ + { version: 2, roots: { __root: [{ path: ["x"], scalar: "toString" }] } }, + {}, + undefined, + /Missing conversion callback/, + ], + [ + { + version: 2, + roots: { __root: [{ path: ["x"], reference: "missing" }] }, + }, + {}, + undefined, + /Missing conversion reference/, + ], + [ + { + version: 2, + roots: { + __root: [ + { path: ["x"], scalar: "a" }, + { path: ["x"], scalar: "b" }, + ], + }, + }, + {}, + undefined, + /Conflicting conversion instruction/, + ], + ])( + "rejects invalid plan %# before seeing data", + (plan, callbacks, nullable, error) => { + expect(() => prepareConversion(plan, callbacks, nullable)).toThrow(error); + }, + ); + test.each([ + [{ scalar: "a", opaque: true }, /Conflicting conversion operations/], + [{ scalar: 1 }, /Invalid conversion scalar/], + [{ union: 1 }, /Invalid conversion union/], + [{ reference: 1 }, /Invalid conversion reference/], + [{ opaque: false }, /Invalid conversion opaque/], + [{ fragments: false }, /Invalid conversion fragments/], + [{ list: -1 }, /Invalid conversion list depth/], + [{ list: 1.5 }, /Invalid conversion list depth/], + [{ list: "1" }, /Invalid conversion list depth/], + [{ scalar: "a", fragments: true }, /Leaf conversion/], + [{ union: "a", fragments: true }, /Union fragments/], + ])("rejects conflicting or malformed operation %#", (instruction, error) => { + expect(() => + prepareConversion( + { version: 2, roots: { __root: [{ path: ["x"], ...instruction }] } }, + { a: (v) => v }, + ), + ).toThrow(error); + }); + test("rejects child instructions underneath opaque/scalar/reference boundaries", () => { + expect(() => + prepareConversion({ + version: 2, + roots: { + __root: [ + { path: ["x"], opaque: true }, + { path: ["x", "child"], fragments: true }, + ], + }, + }), + ).toThrow(/Leaf conversion/); + }); + test("identical entries can be repeated and explicitly named roots selected", () => { + const entry = { path: ["x"], scalar: "a" }; + expect( + prepareConversion( + { version: 2, roots: { Other: [entry, entry] } }, + { a: (v) => v + 1 }, + undefined, + "Other", + )({ x: 1 }), + ).toStrictEqual({ x: 2 }); + }); +}); + +test("deterministic generated schema trees agree with independent evaluator and callback traces", () => { + let seed = 0x941bf; + const random = () => { + seed = (Math.imul(seed, 1664525) + 1013904223) >>> 0; + return seed; + }; + function generate(depth) { + if (!depth) + return [scalar("number"), scalar("box"), opaque, object()][random() % 4]; + switch (random() % 5) { + case 0: + return list(generate(depth - 1)); + case 1: + return union("union", { + User: object({ a_b: generate(depth - 1) }), + Page: object({ value: generate(depth - 1) }, true), + }); + default: + return object( + { + a_b: generate(depth - 1), + a: object({ b: generate(depth - 1) }), + other: generate(0), + }, + random() % 3 === 0, + ); + } + } + function payload(schema) { + const n = random() % 10; + if (n === 0) return null; + if (n === 1) return undefined; + switch (schema.kind) { + case "scalar": + return String(random() % 100); + case "opaque": + return [null, { x: null }]; + case "list": + return Array.from({ length: random() % 4 }, () => payload(schema.item)); + case "union": { + const type = random() % 2 ? "User" : "Page"; + return { ...payload(schema.members[type]), __typename: type }; + } + case "object": + return Object.fromEntries( + Object.entries(schema.fields) + .reverse() + .map(([key, field]) => [key, payload(field)]), + ); + } + } + for (let i = 0; i < 150; i++) { + const schema = object({ root: generate(3) }); + const input = freeze(payload(schema)); + const definitions = { __root: schema }; + const plan = freeze(encode(definitions)); + for (const nullable of [null, undefined]) { + const actualTrace = [], + expectedTrace = []; + const callbacks = (trace) => ({ + number: (v) => { + trace.push(["number", v]); + return Number(v); + }, + box: (v) => { + trace.push(["box", v]); + return [v]; + }, + union: (v) => { + trace.push(["union", v]); + return v; + }, + }); + const result = prepareConversion( + plan, + callbacks(actualTrace), + nullable, + )(input); + expect(result).toStrictEqual( + evaluate( + schema, + input, + definitions, + callbacks(expectedTrace), + nullable, + ), + ); + expect(actualTrace).toStrictEqual(expectedTrace); + } + } +}); + +test("read/write round trips retain nullable structure, nested lists and opaque scalar values", () => { + const schema = object({ + nested: list(list(scalar("number"))), + boxed: list(scalar("box")), + json: opaque, + }); + const wire = freeze({ + nested: [["1", null, "2"], null], + boxed: ["x", null, "y"], + json: { value: null }, + }); + const read = prepare( + schema, + { number: (v) => Number(v), box: (v) => [v] }, + undefined, + ); + const write = prepare( + schema, + { number: (v) => String(v), box: (v) => v[0] }, + null, + ); + const decoded = read(wire); + expect(decoded.boxed[0]).toStrictEqual(["x"]); + expect(write(decoded)).toStrictEqual(wire); + expect(decoded.json).toBe(wire.json); +}); diff --git a/packages/rescript-relay/benchmarks/conversion.js b/packages/rescript-relay/benchmarks/conversion.js index 3512acb8..83d3d9fb 100644 --- a/packages/rescript-relay/benchmarks/conversion.js +++ b/packages/rescript-relay/benchmarks/conversion.js @@ -12,7 +12,7 @@ const option = (name) => { return i < 0 ? undefined : args[i + 1]; }; const implementation = option("--implementation"); -const { traverser } = require( +const { traverser, prepareConversion } = require( implementation ? path.resolve(implementation) : "../src/utils", ); const samples = Number(option("--samples") || 15); @@ -46,21 +46,28 @@ function objects(value, seen = new Set()) { } return seen; } +const prepared = args.includes("--prepared"); +if (prepared && !prepareConversion) + throw new Error("Implementation has no prepared converter"); let sink; function batch(fixture, count) { const start = performance.now(); - for (let i = 0; i < count; i++) - sink = traverser(fixture.root, fixture.maps, converters, fixture.nullable); + for (let i = 0; i < count; i++) sink = fixture.convert(fixture.root); return performance.now() - start; } const results = cases.map((fixture) => { const before = v8.deserialize(v8.serialize(fixture.root)); - const converted = traverser( - fixture.root, - fixture.maps, - converters, - fixture.nullable, - ); + let preparationNs; + if (prepared) { + const start = performance.now(); + for (let i = 0; i < 1000; i++) + sink = prepareConversion(fixture.plan, converters, fixture.nullable); + preparationNs = ((performance.now() - start) * 1e6) / 1000; + } + fixture.convert = prepared + ? prepareConversion(fixture.plan, converters, fixture.nullable) + : (value) => traverser(value, fixture.maps, converters, fixture.nullable); + const converted = fixture.convert(fixture.root); assert.deepStrictEqual(dataOnly(converted), fixture.expected, fixture.name); assert.deepStrictEqual( fixture.root, @@ -83,6 +90,7 @@ const results = cases.map((fixture) => { name: fixture.name, iterations, newOutputObjects, + preparationNs, medianNs: median, p10Ns: values[Math.floor(values.length * 0.1)], p90Ns: values[Math.floor(values.length * 0.9)], @@ -90,7 +98,8 @@ const results = cases.map((fixture) => { }; }); const report = { - fixtureVersion: 1, + fixtureVersion: 2, + mode: prepared ? "prepared" : "legacy", node: process.version, platform: `${os.platform()} ${os.arch()}`, cpu: os.cpus()[0].model, diff --git a/packages/rescript-relay/benchmarks/fixtures.js b/packages/rescript-relay/benchmarks/fixtures.js index d21114be..79721ce8 100644 --- a/packages/rescript-relay/benchmarks/fixtures.js +++ b/packages/rescript-relay/benchmarks/fixtures.js @@ -117,3 +117,48 @@ const expected = [ cases.forEach((fixture, i) => { fixture.expected = expected[i]; }); + +// Version 2 plans for the same workloads, with explicit list depth and segments. +const field = (path, instruction) => ({ path, ...instruction }); +const plans = [ + { + __root: [ + field([], { fragments: true }), + field(["status"], { scalar: "enum" }), + ], + }, + { __root: [] }, + { __root: [] }, + { + __root: [ + field(["users", "edges"], { list: 1 }), + field(["users", "edges", "node"], { fragments: true }), + field(["users", "edges", "node", "status"], { scalar: "enum" }), + ], + }, + { + __root: [ + field([], { fragments: true }), + field(["status"], { scalar: "enum" }), + ], + }, + { + __root: [ + field(["members"], { list: 1, union: "union" }), + field(["members", "User"], { fragments: true }), + field(["members", "User", "status"], { scalar: "enum" }), + ], + }, + { __root: [field(["dates"], { list: 1, scalar: "scalar" })] }, + { __root: [field(["items"], { list: 1, opaque: true })] }, + { + __root: [field(["input"], { reference: "Input" })], + Input: [ + field(["status"], { scalar: "enum" }), + field(["children"], { list: 1, reference: "Input" }), + ], + }, +]; +cases.forEach((fixture, i) => { + fixture.plan = { version: 2, roots: plans[i] }; +}); diff --git a/packages/rescript-relay/src/RescriptRelay.res b/packages/rescript-relay/src/RescriptRelay.res index 67265b80..960a8695 100644 --- a/packages/rescript-relay/src/RescriptRelay.res +++ b/packages/rescript-relay/src/RescriptRelay.res @@ -112,6 +112,11 @@ external relayFeatureFlags: featureFlags = "RelayFeatureFlags" @module("./utils") external convertObj: ('a, dict>>, 'b, 'c) => 'd = "traverser" +/**Internal: prepare the compiler's versioned conversion plan once.*/ +@module("./utils") +external prepareConversion: (JSON.t, 'converters, 'nullable) => ('input => 'output) = "prepareConversion" + + let optArrayOfNullableToOptArrayOfOpt: option>> => option< array>, > = x => diff --git a/packages/rescript-relay/src/RescriptRelay.resi b/packages/rescript-relay/src/RescriptRelay.resi index b36eff1f..cf77eb85 100644 --- a/packages/rescript-relay/src/RescriptRelay.resi +++ b/packages/rescript-relay/src/RescriptRelay.resi @@ -210,6 +210,11 @@ external storeRootType: string = "ROOT_TYPE" @module("./utils") external convertObj: ('a, dict>>, 'b, 'c) => 'd = "traverser" +/**Internal: prepare the compiler's versioned conversion plan once.*/ +@module("./utils") +external prepareConversion: (JSON.t, 'converters, 'nullable) => ('input => 'output) = "prepareConversion" + + /**Read the following section on working with the Relay store: https://relay.dev/docs/en/relay-store*/ module RecordProxy: { /**Read the following section on working with the Relay store: https://relay.dev/docs/en/relay-store*/ diff --git a/packages/rescript-relay/src/prepareConversion.js b/packages/rescript-relay/src/prepareConversion.js new file mode 100644 index 00000000..44f2d592 --- /dev/null +++ b/packages/rescript-relay/src/prepareConversion.js @@ -0,0 +1,199 @@ +const hasOwn = (object, key) => + Object.prototype.hasOwnProperty.call(object, key); +const isOption = (value) => value.BS_PRIVATE_NESTED_SOME_NONE >= 0; +const isMetadata = (key) => + key.startsWith("__") && + key !== "__typename" && + key !== "__id" && + !key.startsWith("__relay_internal"); +const identity = (value) => value; + +// Preparation is deliberately separate from response traversal. It validates and +// snapshots compiler metadata once; the returned functions only visit values. +function readPlan(plan) { + if ( + !plan || + plan.version !== 2 || + !plan.roots || + typeof plan.roots !== "object" + ) { + throw new Error("Invalid conversion plan: expected version 2 and roots"); + } + const roots = Object.create(null); + function node() { + return { children: Object.create(null) }; + } + const keys = new Set([ + "path", + "list", + "scalar", + "union", + "reference", + "opaque", + "fragments", + ]); + for (const name of Object.keys(plan.roots)) { + const entries = plan.roots[name]; + if (!Array.isArray(entries)) + throw new Error("Invalid conversion root: " + name); + const root = (roots[name] = node()); + for (const entry of entries) { + if ( + !entry || + !Array.isArray(entry.path) || + !entry.path.every((key) => typeof key === "string") + ) { + throw new Error("Invalid conversion path in " + name); + } + let target = root; + for (const key of entry.path) + target = target.children[key] || (target.children[key] = node()); + for (const key of Object.keys(entry)) { + if (!keys.has(key)) + throw new Error("Unknown conversion instruction: " + key); + if (key === "path") continue; + if (hasOwn(target, key) && target[key] !== entry[key]) + throw new Error("Conflicting conversion instruction: " + key); + target[key] = entry[key]; + } + } + } + return roots; +} + +function prepareConversion(plan, callbacks, nullable, rootName = "__root") { + if (nullable !== undefined && nullable !== null) + throw new Error("Invalid conversion nullable sentinel"); + const roots = readPlan(plan); + if (!hasOwn(roots, rootName)) + throw new Error("Missing conversion root: " + rootName); + const converters = Object.create(null); + + function optional(convert) { + return (value) => + value == null ? nullable : isOption(value) ? value : convert(value); + } + function arrayOf(convert) { + return (values) => { + let result; + for (let i = 0; i < values.length; i++) { + if (!(i in values)) continue; + const value = values[i]; + const next = convert(value); + if (next !== value) { + if (result === undefined) result = values.slice(); + result[i] = next; + } + } + return result === undefined ? values : result; + }; + } + const anyArray = arrayOf((value) => any(value)); + function any(value) { + if (value == null) return nullable; + if (typeof value !== "object" || isOption(value)) return value; + return Array.isArray(value) ? anyArray(value) : plainObject(value); + } + function record(fields, fragments) { + return (value) => { + let result; + if (fragments) { + const refs = { ...value }; + result = { ...value, fragmentRefs: refs, updatableFragmentRefs: refs }; + } + for (const key in value) { + if (!hasOwn(value, key) || isMetadata(key)) continue; + const original = value[key]; + const convert = fields[key]; + const next = convert === undefined ? any(original) : convert(original); + if (next !== original) { + if (result === undefined) result = { ...value }; + result[key] = next; + } + } + return result === undefined ? value : result; + }; + } + const plainObject = record(Object.create(null), false); + function callback(name) { + if ( + !callbacks || + !hasOwn(callbacks, name) || + typeof callbacks[name] !== "function" + ) { + throw new Error("Missing conversion callback: " + name); + } + return callbacks[name]; + } + function compile(node) { + const operations = ["scalar", "union", "reference", "opaque"].filter( + (key) => hasOwn(node, key), + ); + if (operations.length > 1) + throw new Error( + "Conflicting conversion operations: " + operations.join(", "), + ); + for (const key of ["scalar", "union", "reference"]) { + if (hasOwn(node, key) && typeof node[key] !== "string") + throw new Error("Invalid conversion " + key); + } + for (const key of ["opaque", "fragments"]) { + if (hasOwn(node, key) && node[key] !== true) + throw new Error("Invalid conversion " + key); + } + const depth = node.list === undefined ? 0 : node.list; + if (!Number.isSafeInteger(depth) || depth < 0) + throw new Error("Invalid conversion list depth"); + const names = Object.keys(node.children); + let convert; + if ( + node.scalar !== undefined || + node.opaque || + node.reference !== undefined + ) { + if (names.length || node.fragments) + throw new Error( + "Leaf conversion cannot have child fields or fragments", + ); + if (node.scalar !== undefined) convert = callback(node.scalar); + else if (node.opaque) convert = identity; + else { + const target = node.reference; + if (!hasOwn(roots, target)) + throw new Error("Missing conversion reference: " + target); + convert = (value) => + converters[target]( + hasOwn(value, "__$inputUnion") + ? { [value.__$inputUnion]: value._0 } + : value, + ); + } + } else { + const children = Object.create(null); + for (const name of names) children[name] = compile(node.children[name]); + if (node.union !== undefined) { + if (node.fragments) + throw new Error("Union fragments belong on member plans"); + const union = callback(node.union); + convert = + nullable === null + ? (value) => (children[value.__typename] || any)(union(value)) + : (value) => union((children[value.__typename] || any)(value)); + } else convert = record(children, node.fragments === true); + } + convert = optional(convert); + for (let i = 0; i < depth; i++) convert = optional(arrayOf(convert)); + return convert; + } + for (const name of Object.keys(roots)) + converters[name] = compile(roots[name]); + const convert = converters[rootName]; + // Plural fragments share their record/union plan with singular fragments. + const plural = arrayOf(convert); + return (value) => + Array.isArray(value) && roots[rootName].list === undefined + ? plural(value) + : convert(value); +} + +module.exports = { prepareConversion }; diff --git a/packages/rescript-relay/src/utils.js b/packages/rescript-relay/src/utils.js index 645b7ab8..712a97d5 100644 --- a/packages/rescript-relay/src/utils.js +++ b/packages/rescript-relay/src/utils.js @@ -256,4 +256,7 @@ function traverser(root, instructionMaps, converters, nullable, rootObjectKey) { return convertRoot(root); } -module.exports = { traverser }; +module.exports = { + traverser, + prepareConversion: require("./prepareConversion").prepareConversion, +}; From 9cdd68b9c14e0ca1201e5e2e72f8cbbc184e2a6e Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 21 Sep 2026 22:03:15 +0200 Subject: [PATCH 04/23] Generate and validate prepared conversion plans end to end --- .github/workflows/bindings.yml | 3 +- build-ci.sh | 5 +- packages/relay | 2 +- .../__tests__/Test_conversionPlan-tests.js | 85 ++++++ .../__tests__/Test_conversionPlan.res | 11 + .../rescript-relay/__tests__/TestsUtils.res | 14 + .../GroupAvatar_group_graphql.res | 8 +- .../HasNameComponent_hasName_graphql.res | 8 +- ...alUser____relay_model_instance_graphql.res | 8 +- .../__generated__/LocalUser__id_graphql.res | 8 +- .../RelaySchemaAssets_graphql.res | 12 + .../RichContent_content_graphql.res | 8 +- .../TestAliasedFragmentsQuery_graphql.res | 24 +- ...AliasedFragments_userFirstName_graphql.res | 8 +- ...tAliasedFragments_userLastName_graphql.res | 8 +- ...ayUnderlyingScalarSiblingQuery_graphql.res | 24 +- ...TestCatchLoggedInUserPropQuery_graphql.res | 24 +- ...TestCatchMemberPropNestedQuery_graphql.res | 24 +- .../TestCatchMemberPropQuery_graphql.res | 24 +- .../TestCatchMembersPropQuery_graphql.res | 24 +- .../TestCatchUnionMemberQuery_graphql.res | 24 +- .../TestCatchUnionMember_member_graphql.res | 8 +- .../TestCatchUser_user_graphql.res | 8 +- .../TestCodesplitQuery_graphql.res | 24 +- ...CompileInterfacesFragment_user_graphql.res | 8 +- .../TestConnections2_user_graphql.res | 8 +- .../TestConnections3_user_graphql.res | 8 +- .../TestConnectionsQuery_graphql.res | 24 +- ...tConnections_AddFriendMutation_graphql.res | 24 +- .../TestConnections_user_graphql.res | 8 +- .../TestConversionPlanQuery_graphql.res | 261 ++++++++++++++++++ ...larAfterCustomScalarArrayQuery_graphql.res | 24 +- .../TestCustomScalarsQuery_graphql.res | 24 +- .../TestFragmentQuery_graphql.res | 24 +- ...estFragmentRequiredPlural_user_graphql.res | 8 +- .../TestFragmentRequiredQuery_graphql.res | 24 +- .../TestFragmentRequired_user_graphql.res | 8 +- .../TestFragment_allowUnsafeEnum_graphql.res | 8 +- .../TestFragment_inline_graphql.res | 8 +- .../TestFragment_plural_user_graphql.res | 8 +- .../TestFragment_sub_user_graphql.res | 8 +- .../TestFragment_user_graphql.res | 8 +- .../TestInputUnionQuery_graphql.res | 24 +- .../TestLocalPayloadQuery_graphql.res | 40 ++- ...alPayloadViaNodeInterfaceQuery_graphql.res | 40 ++- .../TestLocalPayload_user_graphql.res | 8 +- ...singFieldHandlersLinkedMeQuery_graphql.res | 24 +- ...issingFieldHandlersLinkedQuery_graphql.res | 24 +- ...ieldHandlersPluralBestiesQuery_graphql.res | 24 +- ...issingFieldHandlersPluralQuery_graphql.res | 24 +- ...singFieldHandlersScalarMeQuery_graphql.res | 24 +- ...issingFieldHandlersScalarQuery_graphql.res | 24 +- .../TestMutationInline_user_graphql.res | 8 +- ...tMutationProvidedVariable_user_graphql.res | 8 +- .../TestMutationQuery_graphql.res | 24 +- ...SetOnlineStatusComplexMutation_graphql.res | 24 +- ...utationSetOnlineStatusMutation_graphql.res | 40 ++- ...ragmentSetOnlineStatusMutation_graphql.res | 40 ++- ...ragmentSetOnlineStatusMutation_graphql.res | 40 ++- ...ovidedVariableFragmentMutation_graphql.res | 24 +- .../TestMutation_user_graphql.res | 8 +- ...deInterfaceOnAbstractTypeQuery_graphql.res | 24 +- .../TestNodeInterfaceQuery_graphql.res | 24 +- .../TestNodeInterface_user_graphql.res | 8 +- .../TestNonReactQuery_graphql.res | 24 +- .../TestNonReact_user_graphql.res | 8 +- ...arsAfterCustomScalarArrayQuery_graphql.res | 24 +- .../TestNullableVariablesMutation_graphql.res | 24 +- .../TestNullableVariablesQuery_graphql.res | 24 +- .../TestObserverQuery_graphql.res | 24 +- .../TestPaginationInNodeQuery_graphql.res | 24 +- ...stPaginationInNodeRefetchQuery_graphql.res | 24 +- .../TestPaginationInNode_query_graphql.res | 8 +- .../TestPaginationInNode_user_graphql.res | 8 +- .../TestPaginationUnionQuery_graphql.res | 24 +- ...estPaginationUnionRefetchQuery_graphql.res | 24 +- .../TestPaginationUnion_query_graphql.res | 8 +- .../TestPaginationUnion_user_graphql.res | 8 +- ...estParseCustomScalarArrayQuery_graphql.res | 24 +- ...estPrefetchablePaginationQuery_graphql.res | 24 +- ...etchablePaginationRefetchQuery_graphql.res | 24 +- ...etchablePagination_user__edges_graphql.res | 8 +- ...estPrefetchablePagination_user_graphql.res | 8 +- .../TestProvidedVariablesQuery_graphql.res | 24 +- .../TestProvidedVariables_user_graphql.res | 8 +- .../TestQueryInputObjectsQuery_graphql.res | 24 +- .../__generated__/TestQuery_graphql.res | 24 +- .../TestRefetchingInNodeQuery_graphql.res | 24 +- ...stRefetchingInNodeRefetchQuery_graphql.res | 24 +- .../TestRefetchingInNode_user_graphql.res | 8 +- ...stRefetchingNoArgsRefetchQuery_graphql.res | 24 +- .../TestRefetchingNoArgs_query_graphql.res | 8 +- .../TestRefetchingQuery_graphql.res | 24 +- ...tchingRecordNoArgsRefetchQuery_graphql.res | 24 +- ...stRefetchingRecordNoArgs_query_graphql.res | 8 +- .../TestRefetchingRecordQuery_graphql.res | 24 +- ...stRefetchingRecordRefetchQuery_graphql.res | 24 +- .../TestRefetchingRecord_user_graphql.res | 8 +- .../TestRefetchingRefetchQuery_graphql.res | 24 +- .../TestRefetching_user_graphql.res | 8 +- .../TestRelayResolversAllQuery_graphql.res | 24 +- .../TestRelayResolversQuery_graphql.res | 24 +- .../TestRelayResolvers_user_graphql.res | 8 +- .../TestRelayUserResolver2_graphql.res | 8 +- .../TestRelayUserResolver_graphql.res | 8 +- .../TestRequiredFieldLoggerQuery_graphql.res | 24 +- ...alizeCustomScalarArrayMutation_graphql.res | 24 +- ...eMultipleCustomScalarsMutation_graphql.res | 24 +- ...scriptionProvidedVariable_user_graphql.res | 8 +- .../TestSubscriptionQuery_graphql.res | 24 +- ...riptionUserUpdatedSubscription_graphql.res | 16 +- ...edVariableFragmentSubscription_graphql.res | 16 +- .../TestSubscription_user_graphql.res | 8 +- .../TestTestingHelpersQuery_graphql.res | 40 ++- ...TestTestingHelpers_plural_user_graphql.res | 8 +- .../TestTestingHelpers_sub_user_graphql.res | 8 +- .../TestTestingHelpers_user_graphql.res | 8 +- .../TestUnionFragmentQuery_graphql.res | 24 +- .../TestUnionFragmentUser_user_graphql.res | 8 +- .../TestUnionFragment_member_graphql.res | 8 +- ...estUnionFragment_plural_member_graphql.res | 8 +- .../__generated__/TestUnionsQuery_graphql.res | 24 +- .../TestUpdatableFragmentsQuery_graphql.res | 24 +- .../TestUpdatableFragments_query_graphql.res | 8 +- ...tUpdatableQuery_UpdatableQuery_graphql.res | 8 +- .../TestUpdatableQuery_graphql.res | 24 +- .../__generated__/UserAvatar_user_graphql.res | 8 +- ...erMeta____relay_model_instance_graphql.res | 8 +- .../__generated__/UserName_user_graphql.res | 8 +- .../rescript-relay/__tests__/schema.graphql | 21 ++ .../__tests__/utils-contract-tests.js | 22 ++ .../__tests__/utils-module-tests.js | 35 +++ .../__tests__/utils-prepared-tests.js | 5 +- .../rescript-relay/__tests__/utils-tests.js | 16 +- ...dedQueryProvidedVariables_user_graphql.res | 8 +- .../TestPreloadedQuery_graphql.res | 24 +- ...TestPreloadedQuery_preloadable_graphql.res | 8 +- packages/rescript-relay/benchmarks/README.md | 5 +- .../docs/conversion-contract.md | 17 +- .../rescript-relay/jest.conversion.config.js | 8 +- packages/rescript-relay/package.json | 4 +- packages/rescript-relay/relay.config.js | 1 + .../scripts/build-conversion-modules.js | 25 ++ .../scripts/test-conversion-mutations.js | 68 +++++ packages/rescript-relay/src/RescriptRelay.res | 7 +- .../rescript-relay/src/RescriptRelay.resi | 7 +- .../rescript-relay/src/prepareConversion.js | 15 +- packages/rescript-relay/src/utils.js | 19 +- 148 files changed, 1980 insertions(+), 848 deletions(-) create mode 100644 packages/rescript-relay/__tests__/Test_conversionPlan-tests.js create mode 100644 packages/rescript-relay/__tests__/Test_conversionPlan.res create mode 100644 packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res create mode 100644 packages/rescript-relay/__tests__/utils-module-tests.js create mode 100644 packages/rescript-relay/scripts/build-conversion-modules.js create mode 100644 packages/rescript-relay/scripts/test-conversion-mutations.js diff --git a/.github/workflows/bindings.yml b/.github/workflows/bindings.yml index c9c602bb..a106ad0f 100644 --- a/.github/workflows/bindings.yml +++ b/.github/workflows/bindings.yml @@ -43,8 +43,9 @@ jobs: yarn test:ci ENABLE_PERSISTING=true yarn test:ci yarn test:conversion + yarn test:conversion:mutations - name: Conversion benchmark (informational) - run: yarn bench:conversion --samples 7 --duration 20 --output conversion-benchmark.json + run: yarn bench:conversion:prepared --samples 7 --duration 20 --output conversion-benchmark.json - uses: actions/upload-artifact@v4 with: name: conversion-performance diff --git a/build-ci.sh b/build-ci.sh index d2310d37..fcb194a0 100755 --- a/build-ci.sh +++ b/build-ci.sh @@ -26,9 +26,8 @@ cp .npmignore ../../_release/; cp ../../README.md ../../_release/; cp ../../CHANGELOG.md ../../_release/; -# copy and create mjs version of utils.js -cp src/utils.js ../../_release/src/utils.mjs; -sed -i 's/module\.exports \= /export /g' ../../_release/src/utils.mjs; +# Build matching ESM conversion modules from the CommonJS source. +node scripts/build-conversion-modules.js ../../_release/src; # copy config files echo "Copying config files..." diff --git a/packages/relay b/packages/relay index ef6d6832..6cdc0680 160000 --- a/packages/relay +++ b/packages/relay @@ -1 +1 @@ -Subproject commit ef6d68326a6661887a2a09fd12028f201e32d78f +Subproject commit 6cdc068080bc85a01ec88cd6a556f33551212b3f diff --git a/packages/rescript-relay/__tests__/Test_conversionPlan-tests.js b/packages/rescript-relay/__tests__/Test_conversionPlan-tests.js new file mode 100644 index 00000000..aef6ccfb --- /dev/null +++ b/packages/rescript-relay/__tests__/Test_conversionPlan-tests.js @@ -0,0 +1,85 @@ +require("@testing-library/jest-dom/extend-expect"); +const React = require("react"); +const { render, screen, act } = require("@testing-library/react"); +const { RelayEnvironmentProvider } = require("react-relay"); +const { createMockEnvironment } = require("relay-test-utils"); +const { createOperationDescriptor } = require("relay-runtime"); +const { Query } = require("./Test_conversionPlan.bs"); +const generated = require("./__generated__/TestConversionPlanQuery_graphql.bs"); + +test("compiler plans preserve nulls, nested list depth and distinct paths through mounted hooks and writes", () => { + const environment = createMockEnvironment(); + const variables = { + input: { + grid: [[[1], undefined, [2]], undefined], + children: [{ grid: [[[3]]] }, undefined], + }, + }; + const convertedVariables = Query.convertVariables(variables); + expect(JSON.parse(JSON.stringify(convertedVariables))).toStrictEqual({ + input: { grid: [[1, null, 2], null], children: [{ grid: [[3]] }, null] }, + }); + const operation = createOperationDescriptor( + generated.node, + convertedVariables, + ); + const date = "2020-01-01T00:00:00.000Z"; + const raw = { + conversionContract: { + grid: [[1, null, 2], null], + dates: [date, null], + raw: [[[null, { x: null }], null], null], + a_b: 7, + a: { b: date }, + }, + }; + environment.commitPayload(operation, raw); + let data; + function Probe() { + data = Query.use(variables, "store-only"); + return React.createElement( + "div", + null, + data.conversionContract.a?.b?.toISOString() ?? "empty", + ); + } + render( + React.createElement( + RelayEnvironmentProvider, + { environment }, + React.createElement( + React.Suspense, + { fallback: "loading" }, + React.createElement(Probe), + ), + ), + ); + expect(screen.getByText(date)).toBeInTheDocument(); + expect(data.conversionContract).toStrictEqual({ + grid: [[[1], undefined, [2]], undefined], + dates: [new Date(date), undefined], + raw: [[[null, { x: null }], undefined], undefined], + a_b: [7], + a: { b: new Date(date) }, + }); + expect(environment.lookup(operation.fragment).data).toStrictEqual(raw); + expect(generated.Internal.convertWrapResponse(data)).toStrictEqual(raw); + act(() => + environment.commitPayload(operation, { + conversionContract: { + grid: null, + dates: null, + raw: null, + a_b: null, + a: null, + }, + }), + ); + expect(data.conversionContract).toStrictEqual({ + grid: undefined, + dates: undefined, + raw: undefined, + a_b: undefined, + a: undefined, + }); +}); diff --git a/packages/rescript-relay/__tests__/Test_conversionPlan.res b/packages/rescript-relay/__tests__/Test_conversionPlan.res new file mode 100644 index 00000000..7e540ebd --- /dev/null +++ b/packages/rescript-relay/__tests__/Test_conversionPlan.res @@ -0,0 +1,11 @@ +module Query = %relay(` + query TestConversionPlanQuery($input: ConversionContractInput) { + conversionContract(input: $input) { + grid + dates + raw + a_b + a { b } + } + } +`) diff --git a/packages/rescript-relay/__tests__/TestsUtils.res b/packages/rescript-relay/__tests__/TestsUtils.res index a6604b59..aff75285 100644 --- a/packages/rescript-relay/__tests__/TestsUtils.res +++ b/packages/rescript-relay/__tests__/TestsUtils.res @@ -83,3 +83,17 @@ module ObjectScalar2 = { {a: "parsed2"} } } + +// An array-valued scalar distinguishes scalar arrays from GraphQL list layers. +module ConversionNumber = { + type t = array + + let parse = (value: JSON.t): t => + switch value->JSON.Decode.float { + | Some(number) => [number->Float.toInt] + | None => throw(Malformed_number) + } + + let serialize = (value: t): JSON.t => + value->Array.reduce(0, (total, item) => total + item)->JSON.Encode.int +} diff --git a/packages/rescript-relay/__tests__/__generated__/GroupAvatar_group_graphql.res b/packages/rescript-relay/__tests__/__generated__/GroupAvatar_group_graphql.res index 72663d7e..f63c1c69 100644 --- a/packages/rescript-relay/__tests__/__generated__/GroupAvatar_group_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/GroupAvatar_group_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/HasNameComponent_hasName_graphql.res b/packages/rescript-relay/__tests__/__generated__/HasNameComponent_hasName_graphql.res index 57a02f49..c829d3d8 100644 --- a/packages/rescript-relay/__tests__/__generated__/HasNameComponent_hasName_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/HasNameComponent_hasName_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/LocalUser____relay_model_instance_graphql.res b/packages/rescript-relay/__tests__/__generated__/LocalUser____relay_model_instance_graphql.res index f9daa1d8..bc87cdfa 100644 --- a/packages/rescript-relay/__tests__/__generated__/LocalUser____relay_model_instance_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/LocalUser____relay_model_instance_graphql.res @@ -11,17 +11,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/LocalUser__id_graphql.res b/packages/rescript-relay/__tests__/__generated__/LocalUser__id_graphql.res index 2557adba..78b9d916 100644 --- a/packages/rescript-relay/__tests__/__generated__/LocalUser__id_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/LocalUser__id_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/RelaySchemaAssets_graphql.res b/packages/rescript-relay/__tests__/__generated__/RelaySchemaAssets_graphql.res index fa68111d..bcfc2a73 100644 --- a/packages/rescript-relay/__tests__/__generated__/RelaySchemaAssets_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/RelaySchemaAssets_graphql.res @@ -260,3 +260,15 @@ and input_SerializeMultipleCustomScalars_nullable = { os1s: array, os2?: Null.t, } + +@live +and input_ConversionContractInput = { + grid?: array>>>, + children?: array>, +} + +@live +and input_ConversionContractInput_nullable = { + grid?: Null.t>>>>, + children?: Null.t>>, +} diff --git a/packages/rescript-relay/__tests__/__generated__/RichContent_content_graphql.res b/packages/rescript-relay/__tests__/__generated__/RichContent_content_graphql.res index 909ce99b..9388c973 100644 --- a/packages/rescript-relay/__tests__/__generated__/RichContent_content_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/RichContent_content_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res index 293316b5..9665456b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res @@ -34,45 +34,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res index b10d6e18..7ebd9389 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res index fe8c1084..e9ec2b37 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res index 762cd1a3..bbf4e10b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res @@ -40,8 +40,8 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"__root":{"beforeDate":{"c":"TestsUtils.Datetime"},"aaNumber":{"c":"TestsUtils.Number"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["aaNumber"],"scalar":"TestsUtils.Number"},{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let variablesConverterMap = { @@ -49,39 +49,45 @@ module Internal = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friends"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friends"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res index aa7641fc..5be1a69b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res @@ -26,49 +26,55 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_createdAt_value":{"c":"TestsUtils.Datetime"},"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"path":["loggedInUser","createdAt","value"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let wrapResponseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_createdAt_value":{"c":"TestsUtils.Datetime"},"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"path":["loggedInUser","createdAt","value"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let responseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res index 94edaecf..65705566 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res @@ -47,22 +47,24 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"member_User_memberOfSingular_value_User_createdAt":{"c":"TestsUtils.Datetime"},"member_User_memberOfSingular_value":{"u":"response_member_User_memberOfSingular_value"},"member":{"u":"response_member"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["member"],"union":"response_member"},{"path":["member","User","memberOfSingular","value"],"union":"response_member_User_memberOfSingular_value"},{"path":["member","User","memberOfSingular","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let wrapResponseConverterMap = { @@ -71,16 +73,18 @@ module Internal = { "response_member": wrap_response_member, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"member_User_memberOfSingular_value_User_createdAt":{"c":"TestsUtils.Datetime"},"member_User_memberOfSingular_value":{"u":"response_member_User_memberOfSingular_value"},"member":{"u":"response_member"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["member"],"union":"response_member"},{"path":["member","User","memberOfSingular","value"],"union":"response_member_User_memberOfSingular_value"},{"path":["member","User","memberOfSingular","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let responseConverterMap = { @@ -89,11 +93,13 @@ module Internal = { "response_member": unwrap_response_member, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res index a9a3bc37..4ac3e35d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res @@ -34,22 +34,24 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"member_value_User_createdAt":{"c":"TestsUtils.Datetime"},"member_value":{"u":"response_member_value"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["member","value"],"union":"response_member_value"},{"path":["member","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let wrapResponseConverterMap = { @@ -57,16 +59,18 @@ module Internal = { "response_member_value": wrap_response_member_value, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"member_value_User_createdAt":{"c":"TestsUtils.Datetime"},"member_value":{"u":"response_member_value"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["member","value"],"union":"response_member_value"},{"path":["member","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let responseConverterMap = { @@ -74,11 +78,13 @@ module Internal = { "response_member_value": unwrap_response_member_value, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res index ab98d67e..f7bd5e8b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res @@ -40,22 +40,24 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"members_edges_node_value_User_createdAt":{"c":"TestsUtils.Datetime"},"members_edges_node_value":{"u":"response_members_edges_node_value"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node","value"],"union":"response_members_edges_node_value"},{"path":["members","edges","node","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let wrapResponseConverterMap = { @@ -63,16 +65,18 @@ module Internal = { "response_members_edges_node_value": wrap_response_members_edges_node_value, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"members_edges_node_value_User_createdAt":{"c":"TestsUtils.Datetime"},"members_edges_node_value":{"u":"response_members_edges_node_value"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node","value"],"union":"response_members_edges_node_value"},{"path":["members","edges","node","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let responseConverterMap = { @@ -80,11 +84,13 @@ module Internal = { "response_members_edges_node_value": unwrap_response_members_edges_node_value, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res index 6414b720..e6fd657f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res @@ -25,45 +25,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"member":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"member":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res index c563502a..0a9f1967 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res @@ -30,8 +30,8 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"value_User_createdAt":{"c":"TestsUtils.Datetime"},"value":{"u":"fragment_t"}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["value"],"union":"fragment_t"},{"path":["value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let fragmentConverterMap = { @@ -39,11 +39,13 @@ module Internal = { "fragment_t": unwrap_fragment_t, } @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res index 1736e957..0da46b47 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res @@ -14,19 +14,21 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"value_createdAt":{"c":"TestsUtils.Datetime"}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["value","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let fragmentConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, } @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestCodesplitQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCodesplitQuery_graphql.res index ae4a4053..430eaa1a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCodesplitQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCodesplitQuery_graphql.res @@ -48,45 +48,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.res index ab1fed00..1f2fff20 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res index 7242bffd..5a811aac 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res @@ -34,19 +34,21 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"member":{"u":"fragment_member"}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["member"],"union":"fragment_member"},{"list":1,"path":["member","User","friendsConnection","edges"]}]},"version":2}` ) @live let fragmentConverterMap = { "fragment_member": unwrap_fragment_member, } @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res index ae2e1b96..9fcb59cd 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res @@ -25,17 +25,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friendsConnection","edges"]}]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res index 2c877f79..2ed5b6f6 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res @@ -33,47 +33,53 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"__root":{"beforeDate":{"c":"TestsUtils.Datetime"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let variablesConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res index 8ff2787e..49744f2e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res @@ -27,45 +27,51 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["connections"]}]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res index 42cc6978..e975830d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res @@ -23,17 +23,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["friendsConnection","edges"]}]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res new file mode 100644 index 00000000..a37f9e88 --- /dev/null +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res @@ -0,0 +1,261 @@ +/* @sourceLoc Test_conversionPlan.res */ +/* @generated */ +%%raw("/* @generated */") +module Types = { + @@warning("-30") + + @live type conversionContractInput = RelaySchemaAssets_graphql.input_ConversionContractInput + type rec response_conversionContract_a = { + b: option, + } + and response_conversionContract = { + a: option, + a_b: option, + dates: option>>, + grid: option>>>>, + raw: option>>>>, + } + type response = { + conversionContract: response_conversionContract, + } + @live + type rawResponse = response + @live + type variables = { + input?: conversionContractInput, + } + @live + type refetchVariables = { + input?: option, + } + @live let makeRefetchVariables = ( + ~input=?, + ): refetchVariables => { + input: ?input + } + +} + + +type queryRef + +module Internal = { + @live + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["input"],"reference":"conversionContractInput"}],"conversionContractInput":[{"list":1,"path":["children"],"reference":"conversionContractInput"},{"list":2,"path":["grid"],"scalar":"TestsUtils.ConversionNumber"}]},"version":2}` + ) + @live + let variablesConverterMap = { + "TestsUtils.ConversionNumber": TestsUtils.ConversionNumber.serialize, + } + @live + let preparedVariablesConverter = RescriptRelay.prepareConversion( + variablesConverter, + variablesConverterMap, + None + ) + @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live + type wrapResponseRaw + @live + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["conversionContract","a","b"],"scalar":"TestsUtils.Datetime"},{"path":["conversionContract","a_b"],"scalar":"TestsUtils.ConversionNumber"},{"list":1,"path":["conversionContract","dates"],"scalar":"TestsUtils.Datetime"},{"list":2,"path":["conversionContract","grid"],"scalar":"TestsUtils.ConversionNumber"},{"list":2,"opaque":true,"path":["conversionContract","raw"]}]},"version":2}` + ) + @live + let wrapResponseConverterMap = { + "TestsUtils.Datetime": TestsUtils.Datetime.serialize, + "TestsUtils.ConversionNumber": TestsUtils.ConversionNumber.serialize, + } + @live + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( + wrapResponseConverter, + wrapResponseConverterMap, + null + ) + @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live + type responseRaw + @live + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["conversionContract","a","b"],"scalar":"TestsUtils.Datetime"},{"path":["conversionContract","a_b"],"scalar":"TestsUtils.ConversionNumber"},{"list":1,"path":["conversionContract","dates"],"scalar":"TestsUtils.Datetime"},{"list":2,"path":["conversionContract","grid"],"scalar":"TestsUtils.ConversionNumber"},{"list":2,"opaque":true,"path":["conversionContract","raw"]}]},"version":2}` + ) + @live + let responseConverterMap = { + "TestsUtils.Datetime": TestsUtils.Datetime.parse, + "TestsUtils.ConversionNumber": TestsUtils.ConversionNumber.parse, + } + @live + let preparedResponseConverter = RescriptRelay.prepareConversion( + responseConverter, + responseConverterMap, + None + ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + type wrapRawResponseRaw = wrapResponseRaw + @live + let convertWrapRawResponse = convertWrapResponse + type rawResponseRaw = responseRaw + @live + let convertRawResponse = convertResponse + type rawPreloadToken<'response> = {source: Nullable.t>} + external tokenToRaw: queryRef => rawPreloadToken = "%identity" +} +module Utils = { + @@warning("-33") + open Types +} + +type relayOperationNode +type operationType = RescriptRelay.queryNode + + +let node: operationType = %raw(json` (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "ConversionContract", + "kind": "LinkedField", + "name": "conversionContract", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "grid", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "dates", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "raw", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "a_b", + "storageKey": null + }, + { + "alias": null, + "args": null, + "concreteType": "ConversionContractNested", + "kind": "LinkedField", + "name": "a", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "b", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ] + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TestConversionPlanQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TestConversionPlanQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "f03d25b7fdf92dbacec1faff37fd288d", + "id": null, + "metadata": {}, + "name": "TestConversionPlanQuery", + "operationKind": "query", + "text": null + } +}; +})() `) + +@live let load: ( + ~environment: RescriptRelay.Environment.t, + ~variables: Types.variables, + ~fetchPolicy: RescriptRelay.fetchPolicy=?, + ~fetchKey: string=?, + ~networkCacheConfig: RescriptRelay.cacheConfig=?, +) => queryRef = ( + ~environment, + ~variables, + ~fetchPolicy=?, + ~fetchKey=?, + ~networkCacheConfig=?, +) => + RescriptRelayReact.loadQuery( + environment, + node, + variables->Internal.convertVariables, + { + fetchKey, + fetchPolicy, + networkCacheConfig, + }, + ) + +@live +let queryRefToObservable = token => { + let raw = token->Internal.tokenToRaw + raw.source->Nullable.toOption +} + +@live +let queryRefToPromise = token => { + Promise.make((resolve, _reject) => { + switch token->queryRefToObservable { + | None => resolve(Error()) + | Some(o) => + open RescriptRelay.Observable + let _: subscription = o->subscribe(makeObserver(~complete=() => resolve(Ok()))) + } + }) +} diff --git a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res index 38b1e859..ddd38a18 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res @@ -25,22 +25,24 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_intStrings":{"ca":"TestsUtils.IntString"},"loggedInUser_createdAt":{"c":"TestsUtils.Datetime"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}` ) @live let wrapResponseConverterMap = { @@ -48,16 +50,18 @@ module Internal = { "TestsUtils.IntString": TestsUtils.IntString.serialize, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_intStrings":{"ca":"TestsUtils.IntString"},"loggedInUser_createdAt":{"c":"TestsUtils.Datetime"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}` ) @live let responseConverterMap = { @@ -65,11 +69,13 @@ module Internal = { "TestsUtils.IntString": TestsUtils.IntString.parse, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res index 870857e7..6d4ffb90 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res @@ -54,8 +54,8 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"__root":{"number":{"c":"TestsUtils.Number"},"beforeDate":{"c":"TestsUtils.Datetime"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` ) @live let variablesConverterMap = { @@ -63,16 +63,18 @@ module Internal = { "TestsUtils.Number": TestsUtils.Number.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"member_User_createdAt":{"c":"TestsUtils.Datetime"},"member":{"u":"response_member"},"loggedInUser_friends_createdAt":{"c":"TestsUtils.Datetime"},"loggedInUser_createdAt":{"c":"TestsUtils.Datetime"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","friends"]},{"path":["loggedInUser","friends","createdAt"],"scalar":"TestsUtils.Datetime"},{"path":["member"],"union":"response_member"},{"path":["member","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let wrapResponseConverterMap = { @@ -80,16 +82,18 @@ module Internal = { "response_member": wrap_response_member, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"member_User_createdAt":{"c":"TestsUtils.Datetime"},"member":{"u":"response_member"},"loggedInUser_friends_createdAt":{"c":"TestsUtils.Datetime"},"loggedInUser_createdAt":{"c":"TestsUtils.Datetime"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","friends"]},{"path":["loggedInUser","friends","createdAt"],"scalar":"TestsUtils.Datetime"},{"path":["member"],"union":"response_member"},{"path":["member","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` ) @live let responseConverterMap = { @@ -97,11 +101,13 @@ module Internal = { "response_member": unwrap_response_member, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res index ee9f89cc..d789a6b3 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res @@ -36,45 +36,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"users_edges_node":{"f":""},"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"users_edges_node":{"f":""},"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.res index 126ab337..a744e8ba 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res index acdc53ac..b3541c7b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res @@ -35,45 +35,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"users_edges_node":{"f":""},"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"users_edges_node":{"f":""},"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequired_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequired_user_graphql.res index ce4570c5..22de3485 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequired_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequired_user_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.res index e4ffbaaf..b6e06932 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_inline_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_inline_graphql.res index 80740d2b..580d3d0e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_inline_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_inline_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_plural_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_plural_user_graphql.res index 7d1e1c22..9c12319d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_plural_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_plural_user_graphql.res @@ -16,17 +16,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_sub_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_sub_user_graphql.res index aff0cdd4..94bc2eec 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_sub_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_sub_user_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res index d64f871c..6f3b4c60 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res @@ -16,17 +16,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res index 3bb7cacf..12dbe9ef 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res @@ -33,45 +33,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"location":{"byLoc":{"r":"byLoc"},"byAddress":{"r":"byAddress"}},"byAddress":{},"byLoc":{},"__root":{"location":{"r":"location"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["location"],"reference":"location"}],"byAddress":[],"byLoc":[],"location":[{"path":["byAddress"],"reference":"byAddress"},{"path":["byLoc"],"reference":"byLoc"}]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res index 57f7d3f4..b1a24eae 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res @@ -93,50 +93,56 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + @live type wrapRawResponseRaw @live - let wrapRawResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_memberOf_Group_topMember":{"u":"rawResponse_loggedInUser_memberOf_Group_topMember"},"loggedInUser_memberOfSingular":{"u":"rawResponse_loggedInUser_memberOfSingular"},"loggedInUser_memberOf":{"u":"rawResponse_loggedInUser_memberOf"}}}` + let wrapRawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","memberOf"],"union":"rawResponse_loggedInUser_memberOf"},{"path":["loggedInUser","memberOf","Group","topMember"],"union":"rawResponse_loggedInUser_memberOf_Group_topMember"},{"path":["loggedInUser","memberOfSingular"],"union":"rawResponse_loggedInUser_memberOfSingular"}]},"version":2}` ) @live let wrapRawResponseConverterMap = { @@ -145,16 +151,18 @@ module Internal = { "rawResponse_loggedInUser_memberOfSingular": wrap_rawResponse_loggedInUser_memberOfSingular, } @live - let convertWrapRawResponse = v => v->RescriptRelay.convertObj( + let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( wrapRawResponseConverter, wrapRawResponseConverterMap, null ) @live + let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) + @live type rawResponseRaw @live - let rawResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_memberOf_Group_topMember":{"u":"rawResponse_loggedInUser_memberOf_Group_topMember"},"loggedInUser_memberOfSingular":{"u":"rawResponse_loggedInUser_memberOfSingular"},"loggedInUser_memberOf":{"u":"rawResponse_loggedInUser_memberOf"}}}` + let rawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","memberOf"],"union":"rawResponse_loggedInUser_memberOf"},{"path":["loggedInUser","memberOf","Group","topMember"],"union":"rawResponse_loggedInUser_memberOf_Group_topMember"},{"path":["loggedInUser","memberOfSingular"],"union":"rawResponse_loggedInUser_memberOfSingular"}]},"version":2}` ) @live let rawResponseConverterMap = { @@ -163,11 +171,13 @@ module Internal = { "rawResponse_loggedInUser_memberOfSingular": unwrap_rawResponse_loggedInUser_memberOfSingular, } @live - let convertRawResponse = v => v->RescriptRelay.convertObj( + let preparedRawResponseConverter = RescriptRelay.prepareConversion( rawResponseConverter, rawResponseConverterMap, None ) + @live + let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) type rawPreloadToken<'response> = {source: Nullable.t>} external tokenToRaw: queryRef => rawPreloadToken = "%identity" } diff --git a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res index 13d059da..ac74cd3c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res @@ -118,54 +118,60 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node_User":{"f":""},"node":{"u":"response_node"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` ) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node_User":{"f":""},"node":{"u":"response_node"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` ) @live let responseConverterMap = { "response_node": unwrap_response_node, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + @live type wrapRawResponseRaw @live - let wrapRawResponseConverter: dict>> = %raw( - json`{"__root":{"node_User_memberOf_Group_topMember":{"u":"rawResponse_node_User_memberOf_Group_topMember"},"node_User_memberOfSingular":{"u":"rawResponse_node_User_memberOfSingular"},"node_User_memberOf":{"u":"rawResponse_node_User_memberOf"},"node":{"u":"rawResponse_node"}}}` + let wrapRawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"rawResponse_node"},{"list":1,"path":["node","User","memberOf"],"union":"rawResponse_node_User_memberOf"},{"path":["node","User","memberOf","Group","topMember"],"union":"rawResponse_node_User_memberOf_Group_topMember"},{"path":["node","User","memberOfSingular"],"union":"rawResponse_node_User_memberOfSingular"}]},"version":2}` ) @live let wrapRawResponseConverterMap = { @@ -175,16 +181,18 @@ module Internal = { "rawResponse_node": wrap_rawResponse_node, } @live - let convertWrapRawResponse = v => v->RescriptRelay.convertObj( + let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( wrapRawResponseConverter, wrapRawResponseConverterMap, null ) @live + let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) + @live type rawResponseRaw @live - let rawResponseConverter: dict>> = %raw( - json`{"__root":{"node_User_memberOf_Group_topMember":{"u":"rawResponse_node_User_memberOf_Group_topMember"},"node_User_memberOfSingular":{"u":"rawResponse_node_User_memberOfSingular"},"node_User_memberOf":{"u":"rawResponse_node_User_memberOf"},"node":{"u":"rawResponse_node"}}}` + let rawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"rawResponse_node"},{"list":1,"path":["node","User","memberOf"],"union":"rawResponse_node_User_memberOf"},{"path":["node","User","memberOf","Group","topMember"],"union":"rawResponse_node_User_memberOf_Group_topMember"},{"path":["node","User","memberOfSingular"],"union":"rawResponse_node_User_memberOfSingular"}]},"version":2}` ) @live let rawResponseConverterMap = { @@ -194,11 +202,13 @@ module Internal = { "rawResponse_node": unwrap_rawResponse_node, } @live - let convertRawResponse = v => v->RescriptRelay.convertObj( + let preparedRawResponseConverter = RescriptRelay.prepareConversion( rawResponseConverter, rawResponseConverterMap, None ) + @live + let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) type rawPreloadToken<'response> = {source: Nullable.t>} external tokenToRaw: queryRef => rawPreloadToken = "%identity" } diff --git a/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res index 41529f74..48086e45 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res @@ -64,8 +64,8 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"memberOf_Group_topMember":{"u":"fragment_memberOf_Group_topMember"},"memberOfSingular":{"u":"fragment_memberOfSingular"},"memberOf":{"u":"fragment_memberOf"}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"fragment_memberOf"},{"path":["memberOf","Group","topMember"],"union":"fragment_memberOf_Group_topMember"},{"path":["memberOfSingular"],"union":"fragment_memberOfSingular"}]},"version":2}` ) @live let fragmentConverterMap = { @@ -74,11 +74,13 @@ module Internal = { "fragment_memberOfSingular": unwrap_fragment_memberOfSingular, } @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.res index 23c6a7a4..f277883b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res index 5852b1b2..2a100177 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res @@ -33,49 +33,55 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node":{"u":"response_node"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` ) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node":{"u":"response_node"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` ) @live let responseConverterMap = { "response_node": unwrap_response_node, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res index e7d1d346..5fcd7aa2 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["onlineBesties"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["onlineBesties"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res index 867b407b..1948f976 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["topOnlineUserList"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["topOnlineUserList"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.res index 94ce9bc8..c347a1c0 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res index 6f37c105..d17f53c1 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res @@ -33,49 +33,55 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node":{"u":"response_node"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` ) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node":{"u":"response_node"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` ) @live let responseConverterMap = { "response_node": unwrap_response_node, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationInline_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationInline_user_graphql.res index 08abfc24..c88250a5 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationInline_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationInline_user_graphql.res @@ -16,17 +16,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationProvidedVariable_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationProvidedVariable_user_graphql.res index deac2a73..d63d306c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationProvidedVariable_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationProvidedVariable_user_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res index ddd1e3da..13cfd6b2 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res index 80abd7ac..c9c675bd 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res @@ -29,47 +29,53 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"recursiveSetOnlineStatusInput":{"someValue":{"c":"TestsUtils.IntString"},"setOnlineStatus":{"r":"setOnlineStatusInput"}},"setOnlineStatusInput":{"someJsonValue":{"b":""},"recursed":{"r":"recursiveSetOnlineStatusInput"}},"__root":{"input":{"r":"setOnlineStatusInput"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["input"],"reference":"setOnlineStatusInput"}],"recursiveSetOnlineStatusInput":[{"path":["setOnlineStatus"],"reference":"setOnlineStatusInput"},{"path":["someValue"],"scalar":"TestsUtils.IntString"}],"setOnlineStatusInput":[{"path":["recursed"],"reference":"recursiveSetOnlineStatusInput"},{"opaque":true,"path":["someJsonValue"]}]},"version":2}` ) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res index de98797d..8f5ffc53 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res @@ -42,73 +42,83 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"setOnlineStatus_user":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"setOnlineStatus_user":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + @live type wrapRawResponseRaw @live - let wrapRawResponseConverter: dict>> = %raw( - json`{}` + let wrapRawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapRawResponseConverterMap = () @live - let convertWrapRawResponse = v => v->RescriptRelay.convertObj( + let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( wrapRawResponseConverter, wrapRawResponseConverterMap, null ) @live + let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) + @live type rawResponseRaw @live - let rawResponseConverter: dict>> = %raw( - json`{}` + let rawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let rawResponseConverterMap = () @live - let convertRawResponse = v => v->RescriptRelay.convertObj( + let preparedRawResponseConverter = RescriptRelay.prepareConversion( rawResponseConverter, rawResponseConverterMap, None ) + @live + let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) } module Utils = { @@warning("-33") diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res index 63e5438e..540f6f7a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res @@ -39,73 +39,83 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"setOnlineStatus_user":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"setOnlineStatus_user":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + @live type wrapRawResponseRaw @live - let wrapRawResponseConverter: dict>> = %raw( - json`{}` + let wrapRawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapRawResponseConverterMap = () @live - let convertWrapRawResponse = v => v->RescriptRelay.convertObj( + let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( wrapRawResponseConverter, wrapRawResponseConverterMap, null ) @live + let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) + @live type rawResponseRaw @live - let rawResponseConverter: dict>> = %raw( - json`{}` + let rawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let rawResponseConverterMap = () @live - let convertRawResponse = v => v->RescriptRelay.convertObj( + let preparedRawResponseConverter = RescriptRelay.prepareConversion( rawResponseConverter, rawResponseConverterMap, None ) + @live + let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) } module Utils = { @@warning("-33") diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res index 911895b6..70877363 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res @@ -61,77 +61,87 @@ let unwrap_rawResponse_setOnlineStatus_user_memberOf: Types.rawResponse_setOnlin let wrap_rawResponse_setOnlineStatus_user_memberOf: Types.rawResponse_setOnlineStatus_user_memberOf => Types.rawResponse_setOnlineStatus_user_memberOf = RescriptRelay_Internal.wrapUnion module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"setOnlineStatus_user":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"setOnlineStatus_user":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + @live type wrapRawResponseRaw @live - let wrapRawResponseConverter: dict>> = %raw( - json`{"__root":{"setOnlineStatus_user_memberOf":{"u":"rawResponse_setOnlineStatus_user_memberOf"}}}` + let wrapRawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["setOnlineStatus","user","memberOf"],"union":"rawResponse_setOnlineStatus_user_memberOf"}]},"version":2}` ) @live let wrapRawResponseConverterMap = { "rawResponse_setOnlineStatus_user_memberOf": wrap_rawResponse_setOnlineStatus_user_memberOf, } @live - let convertWrapRawResponse = v => v->RescriptRelay.convertObj( + let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( wrapRawResponseConverter, wrapRawResponseConverterMap, null ) @live + let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) + @live type rawResponseRaw @live - let rawResponseConverter: dict>> = %raw( - json`{"__root":{"setOnlineStatus_user_memberOf":{"u":"rawResponse_setOnlineStatus_user_memberOf"}}}` + let rawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["setOnlineStatus","user","memberOf"],"union":"rawResponse_setOnlineStatus_user_memberOf"}]},"version":2}` ) @live let rawResponseConverterMap = { "rawResponse_setOnlineStatus_user_memberOf": unwrap_rawResponse_setOnlineStatus_user_memberOf, } @live - let convertRawResponse = v => v->RescriptRelay.convertObj( + let preparedRawResponseConverter = RescriptRelay.prepareConversion( rawResponseConverter, rawResponseConverterMap, None ) + @live + let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) } module Utils = { @@warning("-33") diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res index c35ca0cc..a79edaed 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res @@ -24,45 +24,51 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"updateUserAvatar_user":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["updateUserAvatar","user"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"updateUserAvatar_user":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["updateUserAvatar","user"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res index 170618f3..563f948c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res @@ -34,19 +34,21 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"memberOf":{"u":"fragment_memberOf"}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"fragment_memberOf"}]},"version":2}` ) @live let fragmentConverterMap = { "fragment_memberOf": unwrap_fragment_memberOf, } @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res index 695288ae..8b569331 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res @@ -38,49 +38,55 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node":{"u":"response_node"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` ) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node":{"u":"response_node"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` ) @live let responseConverterMap = { "response_node": unwrap_response_node, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res index f95a6428..5ab00204 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res @@ -50,22 +50,24 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node_User":{"f":""},"node":{"u":"response_node"},"_testExhaustiveInterface":{"u":"response__testExhaustiveInterface"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["_testExhaustiveInterface"],"union":"response__testExhaustiveInterface"},{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` ) @live let wrapResponseConverterMap = { @@ -73,16 +75,18 @@ module Internal = { "response_node": wrap_response_node, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node_User":{"f":""},"node":{"u":"response_node"},"_testExhaustiveInterface":{"u":"response__testExhaustiveInterface"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["_testExhaustiveInterface"],"union":"response__testExhaustiveInterface"},{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` ) @live let responseConverterMap = { @@ -90,11 +94,13 @@ module Internal = { "response_node": unwrap_response_node, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestNodeInterface_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNodeInterface_user_graphql.res index ac772e6b..518f55ef 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNodeInterface_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNodeInterface_user_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res index 65f42ae0..b87cbb37 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res @@ -25,45 +25,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestNonReact_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNonReact_user_graphql.res index d9b6b7c4..fe42f9ba 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNonReact_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNonReact_user_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res index 5cf42bc4..b58f6059 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res @@ -29,49 +29,55 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_intStrings":{"ca":"TestsUtils.IntString"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}` ) @live let wrapResponseConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_intStrings":{"ca":"TestsUtils.IntString"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}` ) @live let responseConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.parse, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res index 5dee5a98..8076f091 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res @@ -29,47 +29,53 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"someInput":{"recursive":{"r":"someInput"},"datetime":{"c":"TestsUtils.Datetime"}},"__root":{"someInput":{"r":"someInput"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["someInput"],"reference":"someInput"}],"someInput":[{"path":["datetime"],"scalar":"TestsUtils.Datetime"},{"path":["recursive"],"reference":"someInput"}]},"version":2}` ) @live let variablesConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, null ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesQuery_graphql.res index 9e4dcc3d..666fe166 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestObserverQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestObserverQuery_graphql.res index d32676d8..48c9b286 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestObserverQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestObserverQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res index 75f623f6..5dae7345 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res @@ -35,45 +35,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res index faac0330..43a306ff 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res @@ -48,45 +48,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res index 122105d0..5ef97604 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res @@ -24,17 +24,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"friendsConnection_edges_node":{"f":""}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["friendsConnection","edges"]},{"fragments":true,"path":["friendsConnection","edges","node"]}]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_user_graphql.res index d24b57e8..bbe56248 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_user_graphql.res @@ -18,17 +18,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res index b07dbef4..1fe3cf65 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res @@ -30,45 +30,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res index a7438813..2a23ee5c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res @@ -43,45 +43,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res index 3044ef3f..44781ea8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res @@ -49,19 +49,21 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"members_edges_node_User":{"f":""},"members_edges_node":{"u":"fragment_members_edges_node"}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"fragment_members_edges_node"},{"list":1,"path":["members","edges","node","Group","adminsConnection","edges"]},{"fragments":true,"path":["members","edges","node","User"]}]},"version":2}` ) @live let fragmentConverterMap = { "fragment_members_edges_node": unwrap_fragment_members_edges_node, } @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_user_graphql.res index 881697e7..e75b0399 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_user_graphql.res @@ -17,17 +17,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res index cc39ff17..15030967 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res @@ -27,49 +27,55 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_intStrings":{"ca":"TestsUtils.IntString"},"loggedInUser_intString":{"c":"TestsUtils.IntString"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["loggedInUser","intString"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","justStrings"]}]},"version":2}` ) @live let wrapResponseConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser_intStrings":{"ca":"TestsUtils.IntString"},"loggedInUser_intString":{"c":"TestsUtils.IntString"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["loggedInUser","intString"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","justStrings"]}]},"version":2}` ) @live let responseConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.parse, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res index f1ac5687..12a9b518 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res index 53215b62..51a4096c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res @@ -44,45 +44,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.res index ceb5e787..9373c95f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.res @@ -19,17 +19,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res index 9474ac3f..26b9dc3f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res @@ -25,17 +25,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"friendsConnection_edges":{"f":""}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"list":1,"path":["friendsConnection","edges"]}]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res index d57b30ba..8b759c9b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res @@ -25,47 +25,53 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"inputC":{"recursiveC":{"r":"inputC"},"intStr":{"c":"TestsUtils.IntString"}},"__root":{"__relay_internal__pv__ProvidedVariablesIntStrArr":{"ca":"TestsUtils.IntString"},"__relay_internal__pv__ProvidedVariablesIntStr":{"c":"TestsUtils.IntString"},"__relay_internal__pv__ProvidedVariablesInputCArr":{"r":"inputC"},"__relay_internal__pv__ProvidedVariablesInputC":{"r":"inputC"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesIntStrArr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}` ) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariables_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariables_user_graphql.res index ce709211..554d0496 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariables_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariables_user_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res index 96258848..f8cf1997 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res @@ -31,45 +31,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"searchInput":{},"__root":{"input":{"r":"searchInput"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["input"],"reference":"searchInput"}],"searchInput":[{"list":1,"path":["names"]}]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res index 3b8db4ff..fb33ee93 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res @@ -41,45 +41,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["users","edges"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["users","edges"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res index 0b5e84fa..95d1193b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res @@ -46,49 +46,55 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node_User":{"f":""},"node":{"u":"response_node"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` ) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node_User":{"f":""},"node":{"u":"response_node"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` ) @live let responseConverterMap = { "response_node": unwrap_response_node, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res index 67f6935b..6b6bc59a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res @@ -44,45 +44,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNode_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNode_user_graphql.res index 662ed47b..02118060 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNode_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNode_user_graphql.res @@ -19,17 +19,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res index dbc361d5..4633832c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res @@ -22,45 +22,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgs_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgs_query_graphql.res index e45518d3..9bb578c3 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgs_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgs_query_graphql.res @@ -16,17 +16,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res index 0abff77c..49c28001 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res @@ -41,8 +41,8 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"__root":{"number":{"c":"TestsUtils.Number"},"beforeDate":{"c":"TestsUtils.Datetime"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` ) @live let variablesConverterMap = { @@ -50,39 +50,45 @@ module Internal = { "TestsUtils.Number": TestsUtils.Number.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res index 9ef6c472..9ab4b5cd 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res @@ -22,45 +22,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.res index a39e76d1..2db3e668 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.res @@ -16,17 +16,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res index d67bd471..fcf1f862 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res @@ -41,8 +41,8 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"__root":{"number":{"c":"TestsUtils.Number"},"beforeDate":{"c":"TestsUtils.Datetime"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` ) @live let variablesConverterMap = { @@ -50,39 +50,45 @@ module Internal = { "TestsUtils.Number": TestsUtils.Number.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res index 65ba518f..1e8f4847 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res @@ -52,8 +52,8 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"__root":{"number":{"c":"TestsUtils.Number"},"beforeDate":{"c":"TestsUtils.Datetime"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` ) @live let variablesConverterMap = { @@ -61,39 +61,45 @@ module Internal = { "TestsUtils.Number": TestsUtils.Number.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res index 09bb452a..bc6b3619 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res @@ -23,17 +23,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res index f146b217..3c2c63c1 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res @@ -52,8 +52,8 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"__root":{"number":{"c":"TestsUtils.Number"},"beforeDate":{"c":"TestsUtils.Datetime"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` ) @live let variablesConverterMap = { @@ -61,39 +61,45 @@ module Internal = { "TestsUtils.Number": TestsUtils.Number.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"node":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res index a4c72777..cf51c023 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res @@ -23,17 +23,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversAllQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversAllQuery_graphql.res index 7c54e405..763ae8d4 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversAllQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversAllQuery_graphql.res @@ -30,45 +30,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res index c1438373..4aa98997 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayResolvers_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayResolvers_user_graphql.res index d3b846b2..9e272876 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayResolvers_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayResolvers_user_graphql.res @@ -15,17 +15,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver2_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver2_graphql.res index 7f8ed039..229d09eb 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver2_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver2_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver_graphql.res index f3bc8ae0..d27ae59f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.res index 21658bf1..fb86fc25 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res index ea015ec6..8c6224c4 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res @@ -22,47 +22,53 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"__root":{"input":{"ca":"TestsUtils.IntString"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["input"],"scalar":"TestsUtils.IntString"}]},"version":2}` ) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res index a1bd34b8..b389208d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res @@ -19,8 +19,8 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"serializeMultipleCustomScalars":{"os2":{"c":"TestsUtils.ObjectScalar2"},"os1s":{"ca":"TestsUtils.ObjectScalar1"}},"__root":{"input":{"r":"serializeMultipleCustomScalars"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["input"],"reference":"serializeMultipleCustomScalars"}],"serializeMultipleCustomScalars":[{"list":1,"path":["os1s"],"scalar":"TestsUtils.ObjectScalar1"},{"path":["os2"],"scalar":"TestsUtils.ObjectScalar2"}]},"version":2}` ) @live let variablesConverterMap = { @@ -28,39 +28,45 @@ module Internal = { "TestsUtils.ObjectScalar2": TestsUtils.ObjectScalar2.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.res index 1b1295be..0345d991 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res index d3d7ce89..e2b8dd92 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res @@ -24,45 +24,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res index eb35c38e..40248408 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res @@ -28,31 +28,35 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"userUpdated_user":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["userUpdated","user"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type rawResponseRaw = responseRaw @live let convertRawResponse = convertResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res index 0cb6416b..bea8a22e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res @@ -26,31 +26,35 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"userUpdated_user":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["userUpdated","user"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type rawResponseRaw = responseRaw @live let convertRawResponse = convertResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscription_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscription_user_graphql.res index 31f8a716..efd4007a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscription_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscription_user_graphql.res @@ -16,17 +16,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res index 3ca7ef4f..55642c0d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res @@ -37,73 +37,83 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + @live type wrapRawResponseRaw @live - let wrapRawResponseConverter: dict>> = %raw( - json`{}` + let wrapRawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapRawResponseConverterMap = () @live - let convertWrapRawResponse = v => v->RescriptRelay.convertObj( + let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( wrapRawResponseConverter, wrapRawResponseConverterMap, null ) @live + let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) + @live type rawResponseRaw @live - let rawResponseConverter: dict>> = %raw( - json`{}` + let rawResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let rawResponseConverterMap = () @live - let convertRawResponse = v => v->RescriptRelay.convertObj( + let preparedRawResponseConverter = RescriptRelay.prepareConversion( rawResponseConverter, rawResponseConverterMap, None ) + @live + let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) type rawPreloadToken<'response> = {source: Nullable.t>} external tokenToRaw: queryRef => rawPreloadToken = "%identity" } diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_plural_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_plural_user_graphql.res index fdd86aff..68f05643 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_plural_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_plural_user_graphql.res @@ -16,17 +16,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_sub_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_sub_user_graphql.res index 39a429c5..1e69bb90 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_sub_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_sub_user_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res index 62f877c5..78ca61bf 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res @@ -16,17 +16,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res index 81cf6d51..66e14dd8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res @@ -25,45 +25,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"member":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"member":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentUser_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentUser_user_graphql.res index 977fec2d..52aa100c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentUser_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentUser_user_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res index 4e402be6..08c4ff23 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res @@ -29,19 +29,21 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"User":{"f":""},"":{"u":"fragment"}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":[],"union":"fragment"},{"fragments":true,"path":["User"]}]},"version":2}` ) @live let fragmentConverterMap = { "fragment": unwrap_fragment, } @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res index 71088d52..595072c1 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res @@ -30,19 +30,21 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"User":{"f":""},"":{"u":"fragment"}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":[],"union":"fragment"},{"fragments":true,"path":["User"]}]},"version":2}` ) @live let fragmentConverterMap = { "fragment": unwrap_fragment, } @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res index f0a2e9e0..68fe16b5 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res @@ -70,22 +70,24 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"members_edges_node_Group_members":{"u":"response_members_edges_node_Group_members"},"members_edges_node":{"u":"response_members_edges_node"}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"response_members_edges_node"},{"list":1,"path":["members","edges","node","Group","members"],"union":"response_members_edges_node_Group_members"}]},"version":2}` ) @live let wrapResponseConverterMap = { @@ -93,16 +95,18 @@ module Internal = { "response_members_edges_node": wrap_response_members_edges_node, } @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"members_edges_node_Group_members":{"u":"response_members_edges_node_Group_members"},"members_edges_node":{"u":"response_members_edges_node"}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"response_members_edges_node"},{"list":1,"path":["members","edges","node","Group","members"],"union":"response_members_edges_node_Group_members"}]},"version":2}` ) @live let responseConverterMap = { @@ -110,11 +114,13 @@ module Internal = { "response_members_edges_node": unwrap_response_members_edges_node, } @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res index 4c937703..91d3da5c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res @@ -25,45 +25,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res index bc7c8a40..53c21260 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res @@ -22,17 +22,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.res index 49977a37..419c37eb 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.res @@ -26,17 +26,19 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) + @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_graphql.res index da75e9d3..dd70b482 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_graphql.res @@ -38,45 +38,51 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let variablesConverterMap = () @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/UserAvatar_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/UserAvatar_user_graphql.res index e8a9be0d..cd31c313 100644 --- a/packages/rescript-relay/__tests__/__generated__/UserAvatar_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/UserAvatar_user_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/UserMeta____relay_model_instance_graphql.res b/packages/rescript-relay/__tests__/__generated__/UserMeta____relay_model_instance_graphql.res index 41ee84c2..d6f9538a 100644 --- a/packages/rescript-relay/__tests__/__generated__/UserMeta____relay_model_instance_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/UserMeta____relay_model_instance_graphql.res @@ -11,17 +11,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/UserName_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/UserName_user_graphql.res index 760a1274..54ec7c33 100644 --- a/packages/rescript-relay/__tests__/__generated__/UserName_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/UserName_user_graphql.res @@ -14,17 +14,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests__/schema.graphql b/packages/rescript-relay/__tests__/schema.graphql index 85f770d6..deaff309 100644 --- a/packages/rescript-relay/__tests__/schema.graphql +++ b/packages/rescript-relay/__tests__/schema.graphql @@ -288,3 +288,24 @@ input SerializeMultipleCustomScalars { os1s: [ObjectScalar1!]! os2: ObjectScalar2 } + +# Conversion protocol regressions: list depth must not be inferred from JS arrays. +extend type Query { + conversionContract(input: ConversionContractInput): ConversionContract! +} +input ConversionContractInput { + grid: [[ConversionNumber]] + children: [ConversionContractInput] +} +type ConversionContract { + grid: [[ConversionNumber]] + dates: [Datetime] + raw: [[JSON]] + a_b: ConversionNumber + a: ConversionContractNested +} +type ConversionContractNested { + b: Datetime +} + +scalar ConversionNumber diff --git a/packages/rescript-relay/__tests__/utils-contract-tests.js b/packages/rescript-relay/__tests__/utils-contract-tests.js index c21464ff..8802c450 100644 --- a/packages/rescript-relay/__tests__/utils-contract-tests.js +++ b/packages/rescript-relay/__tests__/utils-contract-tests.js @@ -387,3 +387,25 @@ test("recursive array roots are converted exactly once, including nullable scala expect(result.after).toBeUndefined(); expect(scalar).toHaveBeenCalledTimes(1); }); + +test("legacy custom scalar lists normalize nulls and preserve nested option markers without invoking callbacks", () => { + const marker = { BS_PRIVATE_NESTED_SOME_NONE: 0 }; + const scalar = jest.fn((v) => ({ value: v })); + const input = freeze({ items: ["a", null, undefined, marker, "b"] }); + const output = traverser( + input, + { __root: { items: { ca: "scalar" } } }, + { scalar }, + ); + expect(output.items).toStrictEqual([ + { value: "a" }, + undefined, + undefined, + marker, + { value: "b" }, + ]); + expect(scalar.mock.calls).toEqual([ + ["a", 0, input.items], + ["b", 4, input.items], + ]); +}); diff --git a/packages/rescript-relay/__tests__/utils-module-tests.js b/packages/rescript-relay/__tests__/utils-module-tests.js new file mode 100644 index 00000000..2f578022 --- /dev/null +++ b/packages/rescript-relay/__tests__/utils-module-tests.js @@ -0,0 +1,35 @@ +const fs=require('fs'); +const os=require('os'); +const path=require('path'); +const {execFile}=require('child_process'); +const execFileAsync=require('util').promisify(execFile); +const {buildConversionModules}=require('../scripts/build-conversion-modules'); + +test('release ESM and CommonJS exports execute the same legacy and prepared conversions',async()=>{ + const directory=fs.mkdtempSync(path.join(os.tmpdir(),'relay-conversion-modules-')); + try { + buildConversionModules(directory); + // Test native ESM, bypassing Jest's dynamic-import-to-require transform. + const program=` + import assert from 'node:assert/strict'; + import {pathToFileURL} from 'node:url'; + import {createRequire} from 'node:module'; + const require=createRequire(import.meta.url); + const esm=await import(pathToFileURL(process.argv[1])); + const cjs=require(process.argv[2]); + assert.deepEqual(Object.keys(esm).sort(),Object.keys(cjs).sort()); + const data={items:['1',null],after:null}; + const legacy={__root:{items:{ca:'scalar'}}}; + const plan={version:2,roots:{__root:[{path:['items'],list:1,scalar:'scalar'}]}}; + for(const nullable of [null,undefined]) { + const expected={items:[1,nullable],after:nullable}; + for(const module of [esm,cjs]) { + assert.deepEqual(module.traverser(data,legacy,{scalar:Number},nullable),expected); + assert.deepEqual(module.runConversion(module.prepareConversion(plan,{scalar:Number},nullable),data),expected); + } + } + assert.deepEqual(data,{items:['1',null],after:null}); + `; + await execFileAsync(process.execPath,['--input-type=module','-e',program,path.join(directory,'utils.mjs'),require.resolve('../src/utils')],{stdio:'pipe'}); + } finally {fs.rmSync(directory,{recursive:true,force:true});} +}); diff --git a/packages/rescript-relay/__tests__/utils-prepared-tests.js b/packages/rescript-relay/__tests__/utils-prepared-tests.js index 5f5df7c2..231ee3c2 100644 --- a/packages/rescript-relay/__tests__/utils-prepared-tests.js +++ b/packages/rescript-relay/__tests__/utils-prepared-tests.js @@ -1,4 +1,4 @@ -const { prepareConversion } = require("../src/utils"); +const { prepareConversion, runConversion } = require("../src/utils"); const { object, list, @@ -11,11 +11,12 @@ const { freeze, } = require("./helpers/conversionModel"); function prepare(schema, converters = {}, nullable, extra = {}) { - return prepareConversion( + const convert = prepareConversion( encode({ __root: schema, ...extra }), converters, nullable, ); + return (value) => runConversion(convert, value); } describe.each([undefined, null])( diff --git a/packages/rescript-relay/__tests__/utils-tests.js b/packages/rescript-relay/__tests__/utils-tests.js index 988817f6..61065a78 100644 --- a/packages/rescript-relay/__tests__/utils-tests.js +++ b/packages/rescript-relay/__tests__/utils-tests.js @@ -1012,12 +1012,7 @@ describe("conversion", () => { expect(spy).not.toHaveBeenCalled(); }); - test("[T]! / [T] — array contains a null element: CURRENT BEHAVIOR calls parse(null)", () => { - // Locks in current behavior. utils.js:109-113 maps `converter` - // over every element with no per-element null check, so a wire - // null reaches user code as `parse(null)`. A future fix should - // produce `[parse("a"), undefined, parse("b")]` — out of scope - // for this PR. + test("[T]! / [T] — nullable elements bypass parse", () => { expect( traverser( { xs: ["a", null, "b"] }, @@ -1025,7 +1020,7 @@ describe("conversion", () => { { [SCALAR]: parse }, undefined ) - ).toEqual({ xs: ["parsed:a", "parsed:null", "parsed:b"] }); + ).toEqual({ xs: ["parsed:a", undefined, "parsed:b"] }); }); test("BS_PRIVATE_NESTED_SOME_NONE on a ca field passes through unchanged", () => { @@ -1068,10 +1063,7 @@ describe("conversion", () => { expect(spy).not.toHaveBeenCalled(); }); - test("[T]! / [T] — array contains null element: CURRENT BEHAVIOR calls serialize(null)", () => { - // Symmetric to the read-side cell of the same name. Out of - // scope for this PR; correct output would be - // `[serialize(10), null, serialize(30)]`. + test("[T]! / [T] — nullable elements bypass serialize", () => { expect( traverser( { xs: [10, null, 30] }, @@ -1082,7 +1074,7 @@ describe("conversion", () => { ).toEqual({ xs: [ { serialized: 10 }, - { serialized: null }, + null, { serialized: 30 }, ], }); diff --git a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.res b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.res index e6bede53..96e98d3d 100644 --- a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.res +++ b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.res @@ -13,17 +13,19 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: dict>> = %raw( - json`{}` + let fragmentConverter: JSON.t = %raw( + json`{"roots":{"__root":[]},"version":2}` ) @live let fragmentConverterMap = () @live - let convertFragment = v => v->RescriptRelay.convertObj( + let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, fragmentConverterMap, None ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } type t diff --git a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res index dd575f06..5029583a 100644 --- a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res +++ b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res @@ -48,47 +48,53 @@ type queryRef module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"inputC":{"recursiveC":{"r":"inputC"},"intStr":{"c":"TestsUtils.IntString"}},"__root":{"__relay_internal__pv__ProvidedVariablesIntStr":{"c":"TestsUtils.IntString"},"__relay_internal__pv__ProvidedVariablesInputCArr":{"r":"inputC"},"__relay_internal__pv__ProvidedVariablesInputC":{"r":"inputC"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}` ) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live type wrapResponseRaw @live - let wrapResponseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let wrapResponseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]}]},"version":2}` ) @live let wrapResponseConverterMap = () @live - let convertWrapResponse = v => v->RescriptRelay.convertObj( + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, wrapResponseConverterMap, null ) @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live type responseRaw @live - let responseConverter: dict>> = %raw( - json`{"__root":{"loggedInUser":{"f":""}}}` + let responseConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]}]},"version":2}` ) @live let responseConverterMap = () @live - let convertResponse = v => v->RescriptRelay.convertObj( + let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, responseConverterMap, None ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res index a516d383..45f7d65e 100644 --- a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res +++ b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res @@ -14,19 +14,21 @@ module Types = { module Internal = { @live - let variablesConverter: dict>> = %raw( - json`{"inputC":{"recursiveC":{"r":"inputC"},"intStr":{"c":"TestsUtils.IntString"}},"__root":{"__relay_internal__pv__ProvidedVariablesIntStr":{"c":"TestsUtils.IntString"},"__relay_internal__pv__ProvidedVariablesInputCArr":{"r":"inputC"},"__relay_internal__pv__ProvidedVariablesInputC":{"r":"inputC"}}}` + let variablesConverter: JSON.t = %raw( + json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}` ) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, } @live - let convertVariables = v => v->RescriptRelay.convertObj( + let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, variablesConverterMap, None ) + @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) } module Utils = { @@warning("-33") diff --git a/packages/rescript-relay/benchmarks/README.md b/packages/rescript-relay/benchmarks/README.md index b81265b8..cc568885 100644 --- a/packages/rescript-relay/benchmarks/README.md +++ b/packages/rescript-relay/benchmarks/README.md @@ -68,8 +68,9 @@ those values remain visible on subsequent calls, without retaining Relay data. Null/undefined handling, opaque JSON blocking, input unions, nested option markers, custom scalar boundaries, and converter order are tested in both directions. In particular, `ca` deliberately retains its existing `Array.map` -semantics: callbacks receive `(value, index, array)`, including null elements. -Changing nullable custom scalar element behavior is outside this optimization. +semantics: nonnull callbacks receive `(value, index, array)`. Null elements now bypass +the callback and normalize to the requested sentinel, as required by the +GraphQL list wrapper. Unchanged roots and arrays may now be returned by identity; consumers must treat converted responses as immutable, just like Relay snapshots. diff --git a/packages/rescript-relay/docs/conversion-contract.md b/packages/rescript-relay/docs/conversion-contract.md index 97fa5ca1..2693751b 100644 --- a/packages/rescript-relay/docs/conversion-contract.md +++ b/packages/rescript-relay/docs/conversion-contract.md @@ -10,7 +10,7 @@ The audited compiler is submodule `ef6d68326a6661887a2a09fd12028f201e32d78f`: `relay-typegen/src/rescript_ast.rs` (`ConverterInstructions`), `rescript.rs` (`ast_to_prop_value`, `write_internal_assets`), and `rescript_utils.rs` (`instruction_to_key_value_pair`). All checked-in generated artifacts were also -inspected. Current compiler opcodes are `c`, `ca`, `r`, `u`, `f`, and `b`; +inspected. Legacy compiler opcodes are `c`, `ca`, `r`, `u`, `f`, and `b`; `e` is retained for older artifacts. Nullable conversion happens implicitly, regardless of historical `n`/`na` hints. Response/fragment conversion, variables, provided variables, mutation/raw responses, and persisted queries use this API. @@ -71,7 +71,7 @@ they belong to the GraphQL nullable wrapper, not the scalar implementation. ## Redesign boundary -New artifacts will use a versioned, lossless plan with path segments and explicit +New artifacts use a versioned, lossless plan with path segments and explicit list depth. Plans are prepared once at module initialization into reusable converters; response conversion does not construct paths or decode opcodes. Prepared converters snapshot their plan and callback bindings; mutating those @@ -98,3 +98,16 @@ callbacks/references and conflicting instructions during preparation. No finite suite proves all possible JavaScript behavior. Confidence depends on this explicit supported contract, independent oracles, real integration tests, and documented remaining limitations—not a claim of absolute certainty. + +## Compiler and package verification + +The compiler changes are in [draft zth/relay#40](https://github.com/zth/relay/pull/40), +pinned by this branch's submodule revision. All 30 compiler library tests pass. +The broader upstream Flow snapshot suite has 64 failures and 93 passes on both +the unchanged pinned compiler and this branch, with identical failing test names. +These existing failures remain outside this conversion change. + +The runtime is tested through both CommonJS and native ESM release modules. +Run `yarn test:all` and `yarn test:conversion:mutations` from the package. The +mutation check runs isolated copies and requires behavioral test failures for +13 deliberately introduced faults; it does not claim a comprehensive mutation score. diff --git a/packages/rescript-relay/jest.conversion.config.js b/packages/rescript-relay/jest.conversion.config.js index 43a91cbd..078512dc 100644 --- a/packages/rescript-relay/jest.conversion.config.js +++ b/packages/rescript-relay/jest.conversion.config.js @@ -5,9 +5,15 @@ module.exports = { testRegex: "/__tests__/utils.*-tests.js$", roots: ["/__tests__"], collectCoverage: true, - collectCoverageFrom: ["src/utils.js"], + collectCoverageFrom: ["src/utils.js", "src/prepareConversion.js"], coverageDirectory: "/coverage/conversion", coverageThreshold: { + "./src/prepareConversion.js": { + branches: 95, + functions: 100, + lines: 100, + statements: 98, + }, "./src/utils.js": { branches: 95, functions: 100, diff --git a/packages/rescript-relay/package.json b/packages/rescript-relay/package.json index 8582dd2a..7d848c01 100644 --- a/packages/rescript-relay/package.json +++ b/packages/rescript-relay/package.json @@ -39,7 +39,9 @@ "test:ci": "jest --ci --runInBand", "test:conversion": "jest --config jest.conversion.config.js --runInBand", "test:all": "yarn build && yarn test:ci && ENABLE_PERSISTING=true yarn test:ci && yarn test:conversion", - "bench:conversion": "node benchmarks/conversion.js" + "bench:conversion": "node benchmarks/conversion.js", + "test:conversion:mutations": "node scripts/test-conversion-mutations.js", + "bench:conversion:prepared": "node benchmarks/conversion.js --prepared" }, "devDependencies": { "@glennsl/rescript-fetch": "^0.2.0", diff --git a/packages/rescript-relay/relay.config.js b/packages/rescript-relay/relay.config.js index 7a83fd75..854df400 100644 --- a/packages/rescript-relay/relay.config.js +++ b/packages/rescript-relay/relay.config.js @@ -13,6 +13,7 @@ module.exports = { IntString: "TestsUtils.IntString", JSON: "JSON.t", Number: "TestsUtils.Number", + ConversionNumber: "TestsUtils.ConversionNumber", ObjectScalar1: "TestsUtils.ObjectScalar1", ObjectScalar2: "TestsUtils.ObjectScalar2", }, diff --git a/packages/rescript-relay/scripts/build-conversion-modules.js b/packages/rescript-relay/scripts/build-conversion-modules.js new file mode 100644 index 00000000..82c319b4 --- /dev/null +++ b/packages/rescript-relay/scripts/build-conversion-modules.js @@ -0,0 +1,25 @@ +#!/usr/bin/env node +// Keep CommonJS and ESM implementations identical. Fail if the source module +// boundary changes instead of producing a silently broken release artifact. +const fs = require('fs'); +const path = require('path'); +function buildConversionModules(destination) { + fs.mkdirSync(destination, {recursive:true}); + for (const name of ['utils','prepareConversion']) { + let source = fs.readFileSync(path.join(__dirname,'../src',name+'.js'),'utf8'); + const exports = /module\.exports = \{([\w\s,]+)\};\s*$/; + if (!exports.test(source)) throw new Error('Unsupported conversion exports in '+name); + source = source.replace(exports,'export {$1};\n'); + if (name === 'utils') { + const dependency = 'const { prepareConversion } = require("./prepareConversion");'; + if (!source.includes(dependency)) throw new Error('Missing prepared-converter import'); + source = source.replace(dependency,'import { prepareConversion } from "./prepareConversion.mjs";'); + } + fs.writeFileSync(path.join(destination,name+'.mjs'),source); + } +} +if (require.main === module) { + if (!process.argv[2]) throw new Error('Usage: build-conversion-modules.js '); + buildConversionModules(path.resolve(process.argv[2])); +} +module.exports = {buildConversionModules}; diff --git a/packages/rescript-relay/scripts/test-conversion-mutations.js b/packages/rescript-relay/scripts/test-conversion-mutations.js new file mode 100644 index 00000000..44828652 --- /dev/null +++ b/packages/rescript-relay/scripts/test-conversion-mutations.js @@ -0,0 +1,68 @@ +#!/usr/bin/env node +// Targeted behavioral mutation checks, not an exhaustive mutation score. +// Run in isolated temporary modules; never rewrite the working source. +const fs = require('fs'); +const os = require('os'); +const path = require('path'); +const {spawn} = require('child_process'); +const root = path.resolve(__dirname,'..'); +const source = fs.readFileSync(path.join(root,'src/prepareConversion.js'),'utf8'); +const directory = fs.mkdtempSync(path.join(os.tmpdir(),'relay-conversion-mutations-')); +const config = {...require('../jest.config'),rootDir:root,bail:false,collectCoverage:false, + roots:[path.join(root,'__tests__')],testRegex:'/utils-prepared-tests.js$'}; +const faults = [ + ['null handling','value == null ? nullable : isOption(value)','value == null ? value : isOption(value)'], + ['option markers','isOption(value) ? value : convert(value)','isOption(value) ? convert(value) : convert(value)'], + ['sparse lists','if (!(i in values)) continue;',''], + ['callback count','const next = convert(value);','const next = convert(convert(value));'], + ['source mutation','if (result === undefined) result = { ...value };','if (result === undefined) result = value;'], + ['shared fragment refs','updatableFragmentRefs: refs','updatableFragmentRefs: { ...refs }'], + ['scalar boundary','convert = callback(node.scalar);','convert = value => any(callback(node.scalar)(value));'], + ['union ordering','(children[value.__typename] || any)(union(value))','union((children[value.__typename] || any)(value))'], + ['union dispatch','children[value.__typename]','children.User'], + ['list depth','i < depth;','i < Math.min(depth, 1);'], + ['path boundaries','for (const key of entry.path)','for (const key of [entry.path.join("_")])'], + ['callback snapshot','return callbacks[name];','return value => callbacks[name](value);'], + ['opaque metadata','!hasOwn(value, key) || isMetadata(key)','!hasOwn(value, key)'], +]; +function run(configuration) { + const file = path.join(directory,'jest.json'); + fs.writeFileSync(file,JSON.stringify(configuration)); + const report = path.join(directory, 'results.json'); + const log = path.join(directory, 'jest.log'); + fs.rmSync(report, {force:true}); + const fd = fs.openSync(log, 'w'); + return new Promise((resolve,reject) => { + const child = spawn(process.execPath,[require.resolve('jest/bin/jest'),'--config',file, + '--runInBand','--no-cache','--json','--outputFile',report], + {cwd:root,stdio:['ignore',fd,fd],env:{...process.env,FORCE_COLOR:'0',CI:'true'}}); + fs.closeSync(fd); + const timer = setTimeout(() => child.kill('SIGKILL'), 30000); + child.on('error', error => {clearTimeout(timer);reject(error);}); + child.on('close', (status,signal) => { + clearTimeout(timer); + const output = fs.readFileSync(log,'utf8'); + if (signal || !fs.existsSync(report)) return reject(new Error('Jest did not complete: '+signal+'\n'+output)); + resolve({status,output,report:JSON.parse(fs.readFileSync(report,'utf8'))}); + }); + }); +} +async function main() { +try { + const control = await run(config); + if (control.status !== 0 || control.report.numPassedTests === 0) throw new Error('Unmodified control failed:\n'+control.output); + for (const [name,before,after] of faults) { + if (!source.includes(before)) throw new Error('Mutation no longer matches source: '+name); + const mutant = path.join(directory,'prepareConversion.js'); + fs.writeFileSync(mutant,source.replace(before,after)); + const result = await run({...config,moduleNameMapper:{'^\\./prepareConversion$':mutant}}); + if (result.status === 0 || result.report.numFailedTests === 0) { + throw new Error('Mutation survived or failed without a behavioral assertion: '+name+'\n'+result.output); + } + process.stdout.write('Detected: '+name+'\n'); + } + process.stdout.write(faults.length+' / '+faults.length+' targeted mutations detected.\n'); +} finally {fs.rmSync(directory,{recursive:true,force:true});} + +} +main().catch(error=>{console.error(error);process.exitCode=1;}); diff --git a/packages/rescript-relay/src/RescriptRelay.res b/packages/rescript-relay/src/RescriptRelay.res index 960a8695..28d58862 100644 --- a/packages/rescript-relay/src/RescriptRelay.res +++ b/packages/rescript-relay/src/RescriptRelay.res @@ -113,8 +113,13 @@ external relayFeatureFlags: featureFlags = "RelayFeatureFlags" external convertObj: ('a, dict>>, 'b, 'c) => 'd = "traverser" /**Internal: prepare the compiler's versioned conversion plan once.*/ +type preparedConversion + +@module("./utils") +external prepareConversion: (JSON.t, 'converters, 'nullable) => preparedConversion = "prepareConversion" + @module("./utils") -external prepareConversion: (JSON.t, 'converters, 'nullable) => ('input => 'output) = "prepareConversion" +external runConversion: (preparedConversion, 'input) => 'output = "runConversion" let optArrayOfNullableToOptArrayOfOpt: option>> => option< diff --git a/packages/rescript-relay/src/RescriptRelay.resi b/packages/rescript-relay/src/RescriptRelay.resi index cf77eb85..101231b7 100644 --- a/packages/rescript-relay/src/RescriptRelay.resi +++ b/packages/rescript-relay/src/RescriptRelay.resi @@ -211,8 +211,13 @@ external storeRootType: string = "ROOT_TYPE" external convertObj: ('a, dict>>, 'b, 'c) => 'd = "traverser" /**Internal: prepare the compiler's versioned conversion plan once.*/ +type preparedConversion + +@module("./utils") +external prepareConversion: (JSON.t, 'converters, 'nullable) => preparedConversion = "prepareConversion" + @module("./utils") -external prepareConversion: (JSON.t, 'converters, 'nullable) => ('input => 'output) = "prepareConversion" +external runConversion: (preparedConversion, 'input) => 'output = "runConversion" /**Read the following section on working with the Relay store: https://relay.dev/docs/en/relay-store*/ diff --git a/packages/rescript-relay/src/prepareConversion.js b/packages/rescript-relay/src/prepareConversion.js index 44f2d592..574aac68 100644 --- a/packages/rescript-relay/src/prepareConversion.js +++ b/packages/rescript-relay/src/prepareConversion.js @@ -6,7 +6,6 @@ const isMetadata = (key) => key !== "__typename" && key !== "__id" && !key.startsWith("__relay_internal"); -const identity = (value) => value; // Preparation is deliberately separate from response traversal. It validates and // snapshots compiler metadata once; the returned functions only visit values. @@ -69,7 +68,9 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { throw new Error("Missing conversion root: " + rootName); const converters = Object.create(null); + const nullableOnly = (value) => (value == null ? nullable : value); function optional(convert) { + if (convert === nullableOnly) return nullableOnly; return (value) => value == null ? nullable : isOption(value) ? value : convert(value); } @@ -156,7 +157,7 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { "Leaf conversion cannot have child fields or fragments", ); if (node.scalar !== undefined) convert = callback(node.scalar); - else if (node.opaque) convert = identity; + else if (node.opaque) convert = nullableOnly; else { const target = node.reference; if (!hasOwn(roots, target)) @@ -190,10 +191,14 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { const convert = converters[rootName]; // Plural fragments share their record/union plan with singular fragments. const plural = arrayOf(convert); + const root = roots[rootName]; + const allowPlural = + root.list === undefined && + root.scalar === undefined && + root.reference === undefined && + !root.opaque; return (value) => - Array.isArray(value) && roots[rootName].list === undefined - ? plural(value) - : convert(value); + Array.isArray(value) && allowPlural ? plural(value) : convert(value); } module.exports = { prepareConversion }; diff --git a/packages/rescript-relay/src/utils.js b/packages/rescript-relay/src/utils.js index 712a97d5..72f80dbc 100644 --- a/packages/rescript-relay/src/utils.js +++ b/packages/rescript-relay/src/utils.js @@ -1,3 +1,5 @@ +const { prepareConversion } = require("./prepareConversion"); + // Shared read-only fallback: avoid allocating an empty map for every field. var empty = Object.freeze({}); @@ -104,8 +106,12 @@ function convertField( var customArray = typeof instruction.ca === "string" && converters[instruction.ca]; if (isArray && customArray) { - // Preserve Array.map's converter calling convention, including null elements. - return value.map(customArray); + // GraphQL null elements belong to the list wrapper, not the scalar parser. + return value.map((item, index, array) => { + if (item == null) return nullable; + if (item.BS_PRIVATE_NESTED_SOME_NONE >= 0) return item; + return customArray(item, index, array); + }); } var blocked = typeof instruction.b === "string"; if (blocked && instruction.b !== "a") return value; @@ -256,7 +262,8 @@ function traverser(root, instructionMaps, converters, nullable, rootObjectKey) { return convertRoot(root); } -module.exports = { - traverser, - prepareConversion: require("./prepareConversion").prepareConversion, -}; +function runConversion(convert, value) { + return convert(value); +} + +module.exports = { traverser, prepareConversion, runConversion }; From e856b907d49a253cbd320cd7836467b77ba64b18 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Mon, 21 Sep 2026 22:07:57 +0200 Subject: [PATCH 05/23] Record balanced conversion benchmarks and finalize validation --- .../__tests__/utils-module-tests.js | 38 +++- .../__tests__/utils-prepared-tests.js | 16 ++ packages/rescript-relay/benchmarks/README.md | 41 ++-- packages/rescript-relay/benchmarks/RESULTS.md | 28 +++ .../results/forward-first-pass.json | 93 ++++++++ .../benchmarks/results/forward-legacy.json | 93 ++++++++ .../benchmarks/results/forward-master.json | 93 ++++++++ .../benchmarks/results/forward-pr-673.json | 93 ++++++++ .../benchmarks/results/forward-prepared.json | 102 +++++++++ .../results/reverse-first-pass.json | 93 ++++++++ .../benchmarks/results/reverse-legacy.json | 93 ++++++++ .../benchmarks/results/reverse-master.json | 93 ++++++++ .../benchmarks/results/reverse-pr-673.json | 93 ++++++++ .../benchmarks/results/reverse-prepared.json | 102 +++++++++ .../scripts/build-conversion-modules.js | 38 ++-- .../scripts/test-conversion-mutations.js | 198 +++++++++++++----- .../rescript-relay/src/prepareConversion.js | 7 +- 17 files changed, 1215 insertions(+), 99 deletions(-) create mode 100644 packages/rescript-relay/benchmarks/RESULTS.md create mode 100644 packages/rescript-relay/benchmarks/results/forward-first-pass.json create mode 100644 packages/rescript-relay/benchmarks/results/forward-legacy.json create mode 100644 packages/rescript-relay/benchmarks/results/forward-master.json create mode 100644 packages/rescript-relay/benchmarks/results/forward-pr-673.json create mode 100644 packages/rescript-relay/benchmarks/results/forward-prepared.json create mode 100644 packages/rescript-relay/benchmarks/results/reverse-first-pass.json create mode 100644 packages/rescript-relay/benchmarks/results/reverse-legacy.json create mode 100644 packages/rescript-relay/benchmarks/results/reverse-master.json create mode 100644 packages/rescript-relay/benchmarks/results/reverse-pr-673.json create mode 100644 packages/rescript-relay/benchmarks/results/reverse-prepared.json diff --git a/packages/rescript-relay/__tests__/utils-module-tests.js b/packages/rescript-relay/__tests__/utils-module-tests.js index 2f578022..e5474ca2 100644 --- a/packages/rescript-relay/__tests__/utils-module-tests.js +++ b/packages/rescript-relay/__tests__/utils-module-tests.js @@ -1,16 +1,20 @@ -const fs=require('fs'); -const os=require('os'); -const path=require('path'); -const {execFile}=require('child_process'); -const execFileAsync=require('util').promisify(execFile); -const {buildConversionModules}=require('../scripts/build-conversion-modules'); +const fs = require("fs"); +const os = require("os"); +const path = require("path"); +const { execFile } = require("child_process"); +const execFileAsync = require("util").promisify(execFile); +const { + buildConversionModules, +} = require("../scripts/build-conversion-modules"); -test('release ESM and CommonJS exports execute the same legacy and prepared conversions',async()=>{ - const directory=fs.mkdtempSync(path.join(os.tmpdir(),'relay-conversion-modules-')); +test("release ESM and CommonJS exports execute the same legacy and prepared conversions", async () => { + const directory = fs.mkdtempSync( + path.join(os.tmpdir(), "relay-conversion-modules-"), + ); try { buildConversionModules(directory); // Test native ESM, bypassing Jest's dynamic-import-to-require transform. - const program=` + const program = ` import assert from 'node:assert/strict'; import {pathToFileURL} from 'node:url'; import {createRequire} from 'node:module'; @@ -30,6 +34,18 @@ test('release ESM and CommonJS exports execute the same legacy and prepared conv } assert.deepEqual(data,{items:['1',null],after:null}); `; - await execFileAsync(process.execPath,['--input-type=module','-e',program,path.join(directory,'utils.mjs'),require.resolve('../src/utils')],{stdio:'pipe'}); - } finally {fs.rmSync(directory,{recursive:true,force:true});} + await execFileAsync( + process.execPath, + [ + "--input-type=module", + "-e", + program, + path.join(directory, "utils.mjs"), + require.resolve("../src/utils"), + ], + { stdio: "pipe" }, + ); + } finally { + fs.rmSync(directory, { recursive: true, force: true }); + } }); diff --git a/packages/rescript-relay/__tests__/utils-prepared-tests.js b/packages/rescript-relay/__tests__/utils-prepared-tests.js index 231ee3c2..c9396a38 100644 --- a/packages/rescript-relay/__tests__/utils-prepared-tests.js +++ b/packages/rescript-relay/__tests__/utils-prepared-tests.js @@ -546,3 +546,19 @@ test("read/write round trips retain nullable structure, nested lists and opaque expect(write(decoded)).toStrictEqual(wire); expect(decoded.json).toBe(wire.json); }); + +// Native scalar lists have list wrappers but no scalar callback instruction. +test("native scalar list plans preserve primitives and normalize nullable members", () => { + const convert = prepareConversion( + { version: 2, roots: { __root: [{ path: ["values"], list: 1 }] } }, + {}, + undefined, + ); + const unchanged = freeze({ + values: ["long string", 0, false, "", undefined], + }); + expect(convert(unchanged)).toBe(unchanged); + expect(convert(freeze({ values: ["x", null, [null]] }))).toStrictEqual({ + values: ["x", undefined, [undefined]], + }); +}); diff --git a/packages/rescript-relay/benchmarks/README.md b/packages/rescript-relay/benchmarks/README.md index cc568885..c47c1c48 100644 --- a/packages/rescript-relay/benchmarks/README.md +++ b/packages/rescript-relay/benchmarks/README.md @@ -4,7 +4,8 @@ Run from `packages/rescript-relay`: ```sh yarn test:all -yarn bench:conversion --output /tmp/conversion-after.json +yarn test:conversion:mutations +yarn bench:conversion:prepared --output /tmp/conversion-after.json ``` `test:all` compiles the checked-in generated Relay artifacts and ReScript bindings, @@ -19,7 +20,7 @@ For a before/after comparison using the **same fixtures and harness**: ```sh git show 520cac4933c118a85cf0dffcd1a19a5dba34ad4f:packages/rescript-relay/src/utils.js > /tmp/utils-before.cjs yarn bench:conversion --implementation /tmp/utils-before.cjs --output /tmp/conversion-before.json -yarn bench:conversion --compare /tmp/conversion-before.json --output /tmp/conversion-after.json +yarn bench:conversion:prepared --compare /tmp/conversion-before.json --output /tmp/conversion-after.json ``` Run those commands sequentially on an otherwise idle machine, with the same Node @@ -53,26 +54,26 @@ compiled query/fragment hooks and store updates without relying on timing. ## Implementation and compatibility -The converter carries encoded string prefixes instead of constructing and -joining path arrays per field. Plain scalar fields take a short path. Lists are -traversed once, each member independently, with lazy copying only when an element -changes. Objects likewise retain identity when nothing changes. Generated -fragment refs are attached while traversing the original object, so they stay raw -and are not visited as new data. Both fragment-ref properties share one snapshot. +New compiler artifacts use version 2 plans: lossless path segments, explicit list +depths, and named scalar/union/reference operations. `prepareConversion` validates +and prepares each plan at module initialization. The response path runs composed +record, list, scalar and union functions without creating paths or interpreting +opcodes. Preparation time is recorded separately as `preparationNs`; it is not +included in warm conversion timings. Prepared converters snapshot callback +bindings and plan metadata; callback state and response data are never cached. -This also removes the old extra recursive-array traversal and the list-wide -union flag that could cause untyped siblings to be skipped. Conversion does not -cache inputs, instruction maps, converter maps, or callback results. Changes to -those values remain visible on subsequent calls, without retaining Relay data. +Lists and records use lazy copying and preserve unchanged branches. Scalar +outputs and JSON remain opaque. Both generated fragment-ref properties point to +one raw snapshot. Null list members bypass scalar callbacks. Union callbacks run +after member conversion for reads and before it for writes, including root unions. -Null/undefined handling, opaque JSON blocking, input unions, nested option -markers, custom scalar boundaries, and converter order are tested in both -directions. In particular, `ca` deliberately retains its existing `Array.map` -semantics: nonnull callbacks receive `(value, index, array)`. Null elements now bypass -the callback and normalize to the requested sentinel, as required by the -GraphQL list wrapper. -Unchanged roots and arrays may now be returned by identity; consumers must treat -converted responses as immutable, just like Relay snapshots. +The legacy `traverser` remains available for existing generated artifacts and can +be measured with `yarn bench:conversion`. It uses string paths and retains the +old protocol's ambiguous underscore paths and inability to encode nested list +depth. Regenerate artifacts with the matching compiler to use prepared plans. +New generated artifacts require this runtime; old generated artifacts still work +with it. See [the conversion contract](../docs/conversion-contract.md) for exact +semantics, intentional bug fixes, supported inputs, and validation boundaries. The existing bindings already memoize conversions with `useMemo` keyed by the Relay snapshot. The mounted regression tests verify unchanged rerenders reuse diff --git a/packages/rescript-relay/benchmarks/RESULTS.md b/packages/rescript-relay/benchmarks/RESULTS.md new file mode 100644 index 00000000..6b040faa --- /dev/null +++ b/packages/rescript-relay/benchmarks/RESULTS.md @@ -0,0 +1,28 @@ +# Prepared conversion benchmark results + +Measured on v24.16.0, AMD RYZEN AI MAX+ 395 w/ Radeon 8060S. Each implementation ran sequentially in forward order, then reverse order; 15 samples per fixture, targeting 40 ms each. Ratios below span those two runs; these are local conversion microbenchmarks, not application latency improvements. + +| Case | Prepared median (µs) | vs master | vs #673 | vs first optimization | +|---|---:|---:|---:|---:| +| small fragment | 0.112–0.121 | 11.51–11.58× | 3.10–3.27× | 2.09–2.33× | +| unchanged object | 0.059–0.062 | 12.80–13.24× | 3.49–3.52× | 1.75–1.97× | +| nullable query | 0.148–0.153 | 13.72–14.10× | 4.13–4.50× | 2.47–2.65× | +| connection / 100 rows | 20.724–24.012 | 30.91–35.23× | 11.43–13.73× | 2.66–3.06× | +| plural fragment / 100 rows | 15.192–16.458 | 8.62–9.50× | 2.23–2.88× | 1.64–2.15× | +| union list / 100 rows | 18.347–18.512 | 12.59–12.62× | 4.43–4.61× | 3.14–3.34× | +| custom scalar list | 12.116–12.560 | 0.88–0.94× | 0.89–0.94× | 0.89–0.92× | +| opaque JSON list | 0.447–0.460 | 1.22–1.24× | 1.47–1.48× | 0.76–0.78× | +| recursive inputs | 16.373–18.089 | 19.19–20.18× | 6.43–7.95× | 1.49–1.81× | + +Ratios above 1 mean prepared conversion was faster. Date construction dominates the custom-scalar fixture: prepared conversion is slightly slower there. Opaque JSON lists are faster than master/#673 but slower than the first legacy optimization. The new representation fixes ambiguous paths and nested-list semantics in addition to avoiding per-response instruction lookup. + +Preparation is outside the timed response path; per-fixture `preparationNs` is reported separately in each prepared JSON file. It is an average over 1,000 preparations, not a startup-latency measurement. `newOutputObjects` counts reachable output objects, not total temporary allocations or retained memory. + +Sources: + +- `master`: `520cac4933c118a85cf0dffcd1a19a5dba34ad4f`, extracted `src/utils.js`. +- `pr-673`: `c451c1afb3193550586f80b36b46b84c8965d355`, extracted `src/utils.js`. +- `first-pass`: `3770abc`, extracted `src/utils.js`. +- `legacy` / `prepared`: the runtime checked in alongside these reports. + +Use the current fixture-version 2 reports named `forward-*.json` and `reverse-*.json` for comparisons. Earlier `baseline.json`, `optimized.json`, and `pr-673.json` are historical fixture-version 1 measurements and must not be mixed with them. See [the benchmark guide](README.md) for commands. diff --git a/packages/rescript-relay/benchmarks/results/forward-first-pass.json b/packages/rescript-relay/benchmarks/results/forward-first-pass.json new file mode 100644 index 00000000..3c13bc2f --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/forward-first-pass.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 2, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "/tmp/relay-conversion-audit/first-pass-utils.cjs", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "medianNs": 261.14952636718755, + "p10Ns": 239.84318359375007, + "p90Ns": 284.6326367187499, + "opsPerSecond": 3829223.8699830407 + }, + { + "name": "unchanged object", + "iterations": 409600, + "newOutputObjects": 0, + "medianNs": 102.91649658203117, + "p10Ns": 100.44872070312516, + "p90Ns": 110.95527832031271, + "opsPerSecond": 9716615.24839154 + }, + { + "name": "nullable query", + "iterations": 102400, + "newOutputObjects": 3, + "medianNs": 366.9991210937473, + "p10Ns": 361.586357421877, + "p90Ns": 380.5079687500035, + "opsPerSecond": 2724802.1657919916 + }, + { + "name": "connection / 100 rows", + "iterations": 800, + "newOutputObjects": 403, + "medianNs": 63887.45624999956, + "p10Ns": 62050.64749999963, + "p90Ns": 68331.1062499996, + "opsPerSecond": 15652.524903900941 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 1600, + "newOutputObjects": 301, + "medianNs": 27059.063124999906, + "p10Ns": 25591.54562499998, + "p90Ns": 30144.928125000093, + "opsPerSecond": 36956.19450608763 + }, + { + "name": "union list / 100 rows", + "iterations": 800, + "newOutputObjects": 302, + "medianNs": 61811.29499999997, + "p10Ns": 59670.634999999944, + "p90Ns": 67804.75000000025, + "opsPerSecond": 16178.272919213236 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "medianNs": 11185.55546875001, + "p10Ns": 10668.467031249946, + "p90Ns": 12038.666562499997, + "opsPerSecond": 89401.01390527996 + }, + { + "name": "opaque JSON list", + "iterations": 204800, + "newOutputObjects": 0, + "medianNs": 341.34198242187443, + "p10Ns": 329.99998046875146, + "p90Ns": 384.9036718750032, + "opsPerSecond": 2929613.266158603 + }, + { + "name": "recursive inputs", + "iterations": 1600, + "newOutputObjects": 103, + "medianNs": 26979.713124999875, + "p10Ns": 26147.026250000064, + "p90Ns": 32104.163125000014, + "opsPerSecond": 37064.88632280462 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/forward-legacy.json b/packages/rescript-relay/benchmarks/results/forward-legacy.json new file mode 100644 index 00000000..1b11f076 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/forward-legacy.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 2, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "medianNs": 253.89532714843733, + "p10Ns": 238.63674804687486, + "p90Ns": 282.41892089843736, + "opsPerSecond": 3938630.975336384 + }, + { + "name": "unchanged object", + "iterations": 409600, + "newOutputObjects": 0, + "medianNs": 106.58042724609406, + "p10Ns": 103.68308105468738, + "p90Ns": 117.37104003906262, + "opsPerSecond": 9382585.769627301 + }, + { + "name": "nullable query", + "iterations": 102400, + "newOutputObjects": 3, + "medianNs": 412.1633984374995, + "p10Ns": 369.64749023437275, + "p90Ns": 488.93430664062487, + "opsPerSecond": 2426222.2307729735 + }, + { + "name": "connection / 100 rows", + "iterations": 800, + "newOutputObjects": 403, + "medianNs": 63942.409999999654, + "p10Ns": 61311.19749999982, + "p90Ns": 70921.94125000048, + "opsPerSecond": 15639.072721844632 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 1600, + "newOutputObjects": 301, + "medianNs": 27282.629375000055, + "p10Ns": 26822.722500000113, + "p90Ns": 28512.498125000147, + "opsPerSecond": 36653.358672105554 + }, + { + "name": "union list / 100 rows", + "iterations": 800, + "newOutputObjects": 302, + "medianNs": 61514.20750000057, + "p10Ns": 58334.78499999955, + "p90Ns": 72838.58874999965, + "opsPerSecond": 16256.407107252267 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "medianNs": 11270.886875000058, + "p10Ns": 10796.85328124995, + "p90Ns": 12141.31828125005, + "opsPerSecond": 88724.16262273902 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 0, + "medianNs": 324.2976953124988, + "p10Ns": 304.1779296875013, + "p90Ns": 364.02474609374735, + "opsPerSecond": 3083586.5146571053 + }, + { + "name": "recursive inputs", + "iterations": 1600, + "newOutputObjects": 103, + "medianNs": 27698.960000000174, + "p10Ns": 27193.85499999987, + "p90Ns": 33138.649375, + "opsPerSecond": 36102.43850310603 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/forward-master.json b/packages/rescript-relay/benchmarks/results/forward-master.json new file mode 100644 index 00000000..dd94a9f3 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/forward-master.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 2, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "/tmp/rescript-relay-utils-baseline.js", + "results": [ + { + "name": "small fragment", + "iterations": 51200, + "newOutputObjects": 3, + "medianNs": 1296.1905664062479, + "p10Ns": 1248.0368164062506, + "p90Ns": 1352.1872265625, + "opsPerSecond": 771491.4966342867 + }, + { + "name": "unchanged object", + "iterations": 102400, + "newOutputObjects": 1, + "medianNs": 752.9779199218777, + "p10Ns": 736.1401269531243, + "p90Ns": 813.7082519531247, + "opsPerSecond": 1328060.1908004833 + }, + { + "name": "nullable query", + "iterations": 25600, + "newOutputObjects": 3, + "medianNs": 2036.2027343749921, + "p10Ns": 1922.2357421874924, + "p90Ns": 2256.0135937500013, + "opsPerSecond": 491110.23333683313 + }, + { + "name": "connection / 100 rows", + "iterations": 100, + "newOutputObjects": 703, + "medianNs": 742242.8299999955, + "p10Ns": 717182.3600000016, + "p90Ns": 790019.7500000014, + "opsPerSecond": 1347.267982366372 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 400, + "newOutputObjects": 301, + "medianNs": 141903.82750000025, + "p10Ns": 133630.61249999874, + "p90Ns": 161153.9425000001, + "opsPerSecond": 7047.026268547959 + }, + { + "name": "union list / 100 rows", + "iterations": 200, + "newOutputObjects": 302, + "medianNs": 233061.77500000104, + "p10Ns": 222003.52000000293, + "p90Ns": 262139.944999999, + "opsPerSecond": 4290.70790351612 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "medianNs": 11033.36984374991, + "p10Ns": 10773.049531249939, + "p90Ns": 11701.395156249959, + "opsPerSecond": 90634.14117006796 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 2, + "medianNs": 552.1257617187558, + "p10Ns": 541.6073339843753, + "p90Ns": 576.928115234372, + "opsPerSecond": 1811181.5628508641 + }, + { + "name": "recursive inputs", + "iterations": 100, + "newOutputObjects": 203, + "medianNs": 347187.9099999933, + "p10Ns": 328057.15000000416, + "p90Ns": 381132.290000005, + "opsPerSecond": 2880.28462742271 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/forward-pr-673.json b/packages/rescript-relay/benchmarks/results/forward-pr-673.json new file mode 100644 index 00000000..745bfa21 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/forward-pr-673.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 2, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "/tmp/relay-conversion-audit/pr-673-utils.cjs", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "medianNs": 347.25091796874995, + "p10Ns": 340.3625537109378, + "p90Ns": 376.1054150390625, + "opsPerSecond": 2879762.0056687444 + }, + { + "name": "unchanged object", + "iterations": 204800, + "newOutputObjects": 1, + "medianNs": 205.458461914062, + "p10Ns": 197.44585449218644, + "p90Ns": 230.86366210937516, + "opsPerSecond": 4867163.857277751 + }, + { + "name": "nullable query", + "iterations": 102400, + "newOutputObjects": 3, + "medianNs": 612.2728515624987, + "p10Ns": 599.0123437500027, + "p90Ns": 665.727714843749, + "opsPerSecond": 1633258.7627363116 + }, + { + "name": "connection / 100 rows", + "iterations": 200, + "newOutputObjects": 703, + "medianNs": 274419.25500000024, + "p10Ns": 266327.060000001, + "p90Ns": 307860.02000000054, + "opsPerSecond": 3644.0591604987744 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 1600, + "newOutputObjects": 301, + "medianNs": 36741.786875000456, + "p10Ns": 36179.95562500027, + "p90Ns": 40977.7943749998, + "opsPerSecond": 27216.966975561325 + }, + { + "name": "union list / 100 rows", + "iterations": 800, + "newOutputObjects": 302, + "medianNs": 81944.94374999977, + "p10Ns": 77201.3250000009, + "p90Ns": 95192.56124999971, + "opsPerSecond": 12203.315473018465 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "medianNs": 11182.258906249983, + "p10Ns": 10639.661406249987, + "p90Ns": 12689.37812499999, + "opsPerSecond": 89427.36958460875 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 2, + "medianNs": 657.8921874999999, + "p10Ns": 640.9829687499968, + "p90Ns": 686.3424511718641, + "opsPerSecond": 1520005.890022824 + }, + { + "name": "recursive inputs", + "iterations": 400, + "newOutputObjects": 203, + "medianNs": 116333.15999999922, + "p10Ns": 111598.26000000066, + "p90Ns": 139304.8100000033, + "opsPerSecond": 8596.00134647771 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/forward-prepared.json b/packages/rescript-relay/benchmarks/results/forward-prepared.json new file mode 100644 index 00000000..36a1470a --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/forward-prepared.json @@ -0,0 +1,102 @@ +{ + "fixtureVersion": 2, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 4519.663999999999, + "medianNs": 111.94897216796868, + "p10Ns": 106.89505615234351, + "p90Ns": 128.51202148437497, + "opsPerSecond": 8932641.190305848 + }, + { + "name": "unchanged object", + "iterations": 819200, + "newOutputObjects": 0, + "preparationNs": 1350.582999999915, + "medianNs": 58.80991210937519, + "p10Ns": 56.25684326171859, + "p90Ns": 65.2856909179686, + "opsPerSecond": 17003936.311623648 + }, + { + "name": "nullable query", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 1025.3990000001068, + "medianNs": 148.41553710937484, + "p10Ns": 145.0156787109369, + "p90Ns": 168.32671142578135, + "opsPerSecond": 6737839.039473677 + }, + { + "name": "connection / 100 rows", + "iterations": 1600, + "newOutputObjects": 403, + "preparationNs": 3402.5219999998626, + "medianNs": 24011.720624999954, + "p10Ns": 23565.928124999973, + "p90Ns": 26119.755624999925, + "opsPerSecond": 41646.328291811114 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 3200, + "newOutputObjects": 301, + "preparationNs": 1177.1159999998417, + "medianNs": 16457.669374999994, + "p10Ns": 16010.871874999993, + "p90Ns": 18624.978750000024, + "opsPerSecond": 60761.94491542338 + }, + { + "name": "union list / 100 rows", + "iterations": 3200, + "newOutputObjects": 302, + "preparationNs": 3215.197000000444, + "medianNs": 18512.08093749989, + "p10Ns": 17770.053437500053, + "p90Ns": 21976.89937500002, + "opsPerSecond": 54018.77851421348 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "preparationNs": 1789.2320000000836, + "medianNs": 12559.793281249937, + "p10Ns": 11876.653593750036, + "p90Ns": 13619.199218749998, + "opsPerSecond": 79619.14480653626 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 0, + "preparationNs": 1626.9050000000789, + "medianNs": 446.64761718749446, + "p10Ns": 422.79999999999876, + "p90Ns": 457.6975195312461, + "opsPerSecond": 2238901.4550148565 + }, + { + "name": "recursive inputs", + "iterations": 3200, + "newOutputObjects": 103, + "preparationNs": 3418.211999999585, + "medianNs": 18089.162812499922, + "p10Ns": 17540.556874999995, + "p90Ns": 19130.46531249989, + "opsPerSecond": 55281.71814059757 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/reverse-first-pass.json b/packages/rescript-relay/benchmarks/results/reverse-first-pass.json new file mode 100644 index 00000000..7aa0ad3d --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/reverse-first-pass.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 2, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "/tmp/relay-conversion-audit/first-pass-utils.cjs", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "medianNs": 253.040908203125, + "p10Ns": 241.3398388671875, + "p90Ns": 281.21173828125, + "opsPerSecond": 3951930.1724812975 + }, + { + "name": "unchanged object", + "iterations": 409600, + "newOutputObjects": 0, + "medianNs": 121.58534667968733, + "p10Ns": 116.83872558593767, + "p90Ns": 143.66232910156205, + "opsPerSecond": 8224675.319094723 + }, + { + "name": "nullable query", + "iterations": 102400, + "newOutputObjects": 3, + "medianNs": 404.78134765625117, + "p10Ns": 396.8749023437512, + "p90Ns": 427.9252929687516, + "opsPerSecond": 2470469.565334866 + }, + { + "name": "connection / 100 rows", + "iterations": 800, + "newOutputObjects": 403, + "medianNs": 63426.453750000175, + "p10Ns": 60388.26125000014, + "p90Ns": 69403.59000000001, + "opsPerSecond": 15766.292152192053 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 1600, + "newOutputObjects": 301, + "medianNs": 32721.201249999864, + "p10Ns": 26765.218125000276, + "p90Ns": 36994.24749999992, + "opsPerSecond": 30561.225193405888 + }, + { + "name": "union list / 100 rows", + "iterations": 800, + "newOutputObjects": 302, + "medianNs": 57567.09124999929, + "p10Ns": 55507.58624999958, + "p90Ns": 62471.36124999997, + "opsPerSecond": 17371.035747789538 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "medianNs": 11124.992968750006, + "p10Ns": 10735.138906249944, + "p90Ns": 12089.70249999993, + "opsPerSecond": 89887.69726048278 + }, + { + "name": "opaque JSON list", + "iterations": 204800, + "newOutputObjects": 0, + "medianNs": 360.07902343750067, + "p10Ns": 341.20398925781444, + "p90Ns": 434.11163574218483, + "opsPerSecond": 2777168.1628479287 + }, + { + "name": "recursive inputs", + "iterations": 1600, + "newOutputObjects": 103, + "medianNs": 29685.76999999982, + "p10Ns": 29033.398749999153, + "p90Ns": 32156.107499999962, + "opsPerSecond": 33686.17354375534 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/reverse-legacy.json b/packages/rescript-relay/benchmarks/results/reverse-legacy.json new file mode 100644 index 00000000..ef520fd5 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/reverse-legacy.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 2, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "medianNs": 260.67492675781233, + "p10Ns": 239.32749023437503, + "p90Ns": 301.7376513671877, + "opsPerSecond": 3836195.572921669 + }, + { + "name": "unchanged object", + "iterations": 409600, + "newOutputObjects": 0, + "medianNs": 112.27575683593726, + "p10Ns": 105.71707031249989, + "p90Ns": 131.49184082031252, + "opsPerSecond": 8906642.254580818 + }, + { + "name": "nullable query", + "iterations": 102400, + "newOutputObjects": 3, + "medianNs": 421.81659179687523, + "p10Ns": 390.69702148437193, + "p90Ns": 462.98953124999986, + "opsPerSecond": 2370698.5913952566 + }, + { + "name": "connection / 100 rows", + "iterations": 800, + "newOutputObjects": 403, + "medianNs": 63811.621250000026, + "p10Ns": 60489.25374999954, + "p90Ns": 72891.10874999949, + "opsPerSecond": 15671.126675848243 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 1600, + "newOutputObjects": 301, + "medianNs": 28267.069999999992, + "p10Ns": 26293.100624999966, + "p90Ns": 34923.04499999989, + "opsPerSecond": 35376.85370291297 + }, + { + "name": "union list / 100 rows", + "iterations": 800, + "newOutputObjects": 302, + "medianNs": 68805.03375000104, + "p10Ns": 60897.09875000039, + "p90Ns": 73596.8562500011, + "opsPerSecond": 14533.82035438628 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "medianNs": 11918.6668750001, + "p10Ns": 11276.09593750009, + "p90Ns": 12962.850000000117, + "opsPerSecond": 83902.00099455264 + }, + { + "name": "opaque JSON list", + "iterations": 204800, + "newOutputObjects": 0, + "medianNs": 297.9844628906259, + "p10Ns": 294.3363525390641, + "p90Ns": 325.21131347655887, + "opsPerSecond": 3355879.6666759313 + }, + { + "name": "recursive inputs", + "iterations": 1600, + "newOutputObjects": 103, + "medianNs": 29947.19562499995, + "p10Ns": 27137.716249999925, + "p90Ns": 34317.94437500002, + "opsPerSecond": 33392.10831364787 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/reverse-master.json b/packages/rescript-relay/benchmarks/results/reverse-master.json new file mode 100644 index 00000000..adfc0356 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/reverse-master.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 2, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "/tmp/rescript-relay-utils-baseline.js", + "results": [ + { + "name": "small fragment", + "iterations": 51200, + "newOutputObjects": 3, + "medianNs": 1390.3375976562502, + "p10Ns": 1310.1150781250005, + "p90Ns": 1465.3082226562497, + "opsPerSecond": 719249.7719156423 + }, + { + "name": "unchanged object", + "iterations": 51200, + "newOutputObjects": 1, + "medianNs": 814.9233984374993, + "p10Ns": 743.1374999999996, + "p90Ns": 938.5449609374996, + "opsPerSecond": 1227109.2005915637 + }, + { + "name": "nullable query", + "iterations": 25600, + "newOutputObjects": 3, + "medianNs": 2151.2362109374903, + "p10Ns": 2004.3573828125006, + "p90Ns": 2345.9887109375013, + "opsPerSecond": 464848.9993408063 + }, + { + "name": "connection / 100 rows", + "iterations": 100, + "newOutputObjects": 703, + "medianNs": 730193.2099999976, + "p10Ns": 713429.6300000006, + "p90Ns": 806732.8899999984, + "opsPerSecond": 1369.5005463006198 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 400, + "newOutputObjects": 301, + "medianNs": 144272.67999999912, + "p10Ns": 137757.06250000212, + "p90Ns": 162907.15249999947, + "opsPerSecond": 6931.319221352276 + }, + { + "name": "union list / 100 rows", + "iterations": 200, + "newOutputObjects": 302, + "medianNs": 231484.95499999626, + "p10Ns": 219309.6400000013, + "p90Ns": 252264.18000000194, + "opsPerSecond": 4319.935176780781 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "medianNs": 11409.869999999955, + "p10Ns": 11052.804374999992, + "p90Ns": 12036.685937500237, + "opsPerSecond": 87643.4174973075 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 2, + "medianNs": 561.9654492187465, + "p10Ns": 547.2058105468758, + "p90Ns": 620.7305273437491, + "opsPerSecond": 1779468.8292495853 + }, + { + "name": "recursive inputs", + "iterations": 200, + "newOutputObjects": 203, + "medianNs": 330408.38999999774, + "p10Ns": 316034.76499999483, + "p90Ns": 367772.06500000827, + "opsPerSecond": 3026.5575277916123 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/reverse-pr-673.json b/packages/rescript-relay/benchmarks/results/reverse-pr-673.json new file mode 100644 index 00000000..e3aec883 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/reverse-pr-673.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 2, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "/tmp/relay-conversion-audit/pr-673-utils.cjs", + "results": [ + { + "name": "small fragment", + "iterations": 102400, + "newOutputObjects": 3, + "medianNs": 395.65080078124976, + "p10Ns": 370.56431640625, + "p90Ns": 475.68430664062464, + "opsPerSecond": 2527481.299230043 + }, + { + "name": "unchanged object", + "iterations": 204800, + "newOutputObjects": 1, + "medianNs": 216.4925732421874, + "p10Ns": 200.19873535156216, + "p90Ns": 236.6231005859376, + "opsPerSecond": 4619096.096572852 + }, + { + "name": "nullable query", + "iterations": 102400, + "newOutputObjects": 3, + "medianNs": 687.3554101562496, + "p10Ns": 636.9974316406247, + "p90Ns": 787.6288378906261, + "opsPerSecond": 1454851.4279864037 + }, + { + "name": "connection / 100 rows", + "iterations": 200, + "newOutputObjects": 703, + "medianNs": 284588.53999999975, + "p10Ns": 251499.08999999982, + "p90Ns": 304142.2499999999, + "opsPerSecond": 3513.844935569088 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 1600, + "newOutputObjects": 301, + "medianNs": 43816.24812499979, + "p10Ns": 37508.75624999992, + "p90Ns": 54928.126874999914, + "opsPerSecond": 22822.583922456844 + }, + { + "name": "union list / 100 rows", + "iterations": 800, + "newOutputObjects": 302, + "medianNs": 84566.53749999987, + "p10Ns": 79368.84999999961, + "p90Ns": 101158.51249999991, + "opsPerSecond": 11825.008207294777 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "medianNs": 11367.214687499825, + "p10Ns": 10906.34343749997, + "p90Ns": 12333.685312499938, + "opsPerSecond": 87972.29818309573 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 2, + "medianNs": 678.9901757812445, + "p10Ns": 657.6561035156292, + "p90Ns": 765.7203320312522, + "opsPerSecond": 1472775.3591565627 + }, + { + "name": "recursive inputs", + "iterations": 400, + "newOutputObjects": 203, + "medianNs": 130241.60999999821, + "p10Ns": 115395.29749999929, + "p90Ns": 147263.88499999756, + "opsPerSecond": 7678.037763814604 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/reverse-prepared.json b/packages/rescript-relay/benchmarks/results/reverse-prepared.json new file mode 100644 index 00000000..da775e64 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/reverse-prepared.json @@ -0,0 +1,102 @@ +{ + "fixtureVersion": 2, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 4430.986000000001, + "medianNs": 120.84148681640622, + "p10Ns": 115.67026367187496, + "p90Ns": 147.16306884765626, + "opsPerSecond": 8275303.67546118 + }, + { + "name": "unchanged object", + "iterations": 819200, + "newOutputObjects": 0, + "preparationNs": 1428.4999999999857, + "medianNs": 61.56754028320333, + "p10Ns": 56.9567492675782, + "p90Ns": 76.20194213867171, + "opsPerSecond": 16242325.020621572 + }, + { + "name": "nullable query", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 933.4850000000188, + "medianNs": 152.60232910156267, + "p10Ns": 143.74919189453104, + "p90Ns": 165.92133056640648, + "opsPerSecond": 6552979.930827018 + }, + { + "name": "connection / 100 rows", + "iterations": 3200, + "newOutputObjects": 403, + "preparationNs": 3173.428999999942, + "medianNs": 20724.01187500006, + "p10Ns": 20384.20375000001, + "p90Ns": 23311.01781249998, + "opsPerSecond": 48253.20531717738 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 3200, + "newOutputObjects": 301, + "preparationNs": 1140.4360000001361, + "medianNs": 15191.98593750019, + "p10Ns": 14558.485312499839, + "p90Ns": 16636.810937500002, + "opsPerSecond": 65824.17888707893 + }, + { + "name": "union list / 100 rows", + "iterations": 3200, + "newOutputObjects": 302, + "preparationNs": 3697.0489999994243, + "medianNs": 18346.74906250001, + "p10Ns": 17551.937499999894, + "p90Ns": 22648.20531250024, + "opsPerSecond": 54505.56916614499 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "preparationNs": 1487.8020000005563, + "medianNs": 12115.780312499994, + "p10Ns": 11397.223593749997, + "p90Ns": 12894.748125000035, + "opsPerSecond": 82536.98682273796 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 0, + "preparationNs": 1891.5559999995821, + "medianNs": 460.2599609374991, + "p10Ns": 447.00962890624754, + "p90Ns": 477.52247070312666, + "opsPerSecond": 2172685.1885250015 + }, + { + "name": "recursive inputs", + "iterations": 3200, + "newOutputObjects": 103, + "preparationNs": 3538.0679999998392, + "medianNs": 16372.539062499527, + "p10Ns": 16073.624062499903, + "p90Ns": 17017.99968749981, + "opsPerSecond": 61077.88145642293 + } + ] +} diff --git a/packages/rescript-relay/scripts/build-conversion-modules.js b/packages/rescript-relay/scripts/build-conversion-modules.js index 82c319b4..dcaf5217 100644 --- a/packages/rescript-relay/scripts/build-conversion-modules.js +++ b/packages/rescript-relay/scripts/build-conversion-modules.js @@ -1,25 +1,35 @@ #!/usr/bin/env node // Keep CommonJS and ESM implementations identical. Fail if the source module // boundary changes instead of producing a silently broken release artifact. -const fs = require('fs'); -const path = require('path'); +const fs = require("fs"); +const path = require("path"); function buildConversionModules(destination) { - fs.mkdirSync(destination, {recursive:true}); - for (const name of ['utils','prepareConversion']) { - let source = fs.readFileSync(path.join(__dirname,'../src',name+'.js'),'utf8'); + fs.mkdirSync(destination, { recursive: true }); + for (const name of ["utils", "prepareConversion"]) { + let source = fs.readFileSync( + path.join(__dirname, "../src", name + ".js"), + "utf8", + ); const exports = /module\.exports = \{([\w\s,]+)\};\s*$/; - if (!exports.test(source)) throw new Error('Unsupported conversion exports in '+name); - source = source.replace(exports,'export {$1};\n'); - if (name === 'utils') { - const dependency = 'const { prepareConversion } = require("./prepareConversion");'; - if (!source.includes(dependency)) throw new Error('Missing prepared-converter import'); - source = source.replace(dependency,'import { prepareConversion } from "./prepareConversion.mjs";'); + if (!exports.test(source)) + throw new Error("Unsupported conversion exports in " + name); + source = source.replace(exports, "export {$1};\n"); + if (name === "utils") { + const dependency = + 'const { prepareConversion } = require("./prepareConversion");'; + if (!source.includes(dependency)) + throw new Error("Missing prepared-converter import"); + source = source.replace( + dependency, + 'import { prepareConversion } from "./prepareConversion.mjs";', + ); } - fs.writeFileSync(path.join(destination,name+'.mjs'),source); + fs.writeFileSync(path.join(destination, name + ".mjs"), source); } } if (require.main === module) { - if (!process.argv[2]) throw new Error('Usage: build-conversion-modules.js '); + if (!process.argv[2]) + throw new Error("Usage: build-conversion-modules.js "); buildConversionModules(path.resolve(process.argv[2])); } -module.exports = {buildConversionModules}; +module.exports = { buildConversionModules }; diff --git a/packages/rescript-relay/scripts/test-conversion-mutations.js b/packages/rescript-relay/scripts/test-conversion-mutations.js index 44828652..aa5f89da 100644 --- a/packages/rescript-relay/scripts/test-conversion-mutations.js +++ b/packages/rescript-relay/scripts/test-conversion-mutations.js @@ -1,68 +1,160 @@ #!/usr/bin/env node // Targeted behavioral mutation checks, not an exhaustive mutation score. // Run in isolated temporary modules; never rewrite the working source. -const fs = require('fs'); -const os = require('os'); -const path = require('path'); -const {spawn} = require('child_process'); -const root = path.resolve(__dirname,'..'); -const source = fs.readFileSync(path.join(root,'src/prepareConversion.js'),'utf8'); -const directory = fs.mkdtempSync(path.join(os.tmpdir(),'relay-conversion-mutations-')); -const config = {...require('../jest.config'),rootDir:root,bail:false,collectCoverage:false, - roots:[path.join(root,'__tests__')],testRegex:'/utils-prepared-tests.js$'}; +const fs = require("fs"); +const os = require("os"); +const path = require("path"); +const { spawn } = require("child_process"); +const root = path.resolve(__dirname, ".."); +const source = fs.readFileSync( + path.join(root, "src/prepareConversion.js"), + "utf8", +); +const directory = fs.mkdtempSync( + path.join(os.tmpdir(), "relay-conversion-mutations-"), +); +const config = { + ...require("../jest.config"), + rootDir: root, + bail: false, + collectCoverage: false, + roots: [path.join(root, "__tests__")], + testRegex: "/utils-prepared-tests.js$", +}; const faults = [ - ['null handling','value == null ? nullable : isOption(value)','value == null ? value : isOption(value)'], - ['option markers','isOption(value) ? value : convert(value)','isOption(value) ? convert(value) : convert(value)'], - ['sparse lists','if (!(i in values)) continue;',''], - ['callback count','const next = convert(value);','const next = convert(convert(value));'], - ['source mutation','if (result === undefined) result = { ...value };','if (result === undefined) result = value;'], - ['shared fragment refs','updatableFragmentRefs: refs','updatableFragmentRefs: { ...refs }'], - ['scalar boundary','convert = callback(node.scalar);','convert = value => any(callback(node.scalar)(value));'], - ['union ordering','(children[value.__typename] || any)(union(value))','union((children[value.__typename] || any)(value))'], - ['union dispatch','children[value.__typename]','children.User'], - ['list depth','i < depth;','i < Math.min(depth, 1);'], - ['path boundaries','for (const key of entry.path)','for (const key of [entry.path.join("_")])'], - ['callback snapshot','return callbacks[name];','return value => callbacks[name](value);'], - ['opaque metadata','!hasOwn(value, key) || isMetadata(key)','!hasOwn(value, key)'], + [ + "null handling", + "value == null ? nullable : isOption(value)", + "value == null ? value : isOption(value)", + ], + [ + "option markers", + "isOption(value) ? value : convert(value)", + "isOption(value) ? convert(value) : convert(value)", + ], + ["sparse lists", "if (!(i in values)) continue;", ""], + [ + "callback count", + "const next = convert(value);", + "const next = convert(convert(value));", + ], + [ + "source mutation", + "if (result === undefined) result = { ...value };", + "if (result === undefined) result = value;", + ], + [ + "shared fragment refs", + "updatableFragmentRefs: refs", + "updatableFragmentRefs: { ...refs }", + ], + [ + "scalar boundary", + "convert = callback(node.scalar);", + "convert = value => any(callback(node.scalar)(value));", + ], + [ + "union ordering", + "(children[value.__typename] || any)(union(value))", + "union((children[value.__typename] || any)(value))", + ], + ["union dispatch", "children[value.__typename]", "children.User"], + ["list depth", "i < depth;", "i < Math.min(depth, 1);"], + [ + "path boundaries", + "for (const key of entry.path)", + 'for (const key of [entry.path.join("_")])', + ], + [ + "callback snapshot", + "return callbacks[name];", + "return value => callbacks[name](value);", + ], + [ + "opaque metadata", + "!hasOwn(value, key) || isMetadata(key)", + "!hasOwn(value, key)", + ], ]; function run(configuration) { - const file = path.join(directory,'jest.json'); - fs.writeFileSync(file,JSON.stringify(configuration)); - const report = path.join(directory, 'results.json'); - const log = path.join(directory, 'jest.log'); - fs.rmSync(report, {force:true}); - const fd = fs.openSync(log, 'w'); - return new Promise((resolve,reject) => { - const child = spawn(process.execPath,[require.resolve('jest/bin/jest'),'--config',file, - '--runInBand','--no-cache','--json','--outputFile',report], - {cwd:root,stdio:['ignore',fd,fd],env:{...process.env,FORCE_COLOR:'0',CI:'true'}}); + const file = path.join(directory, "jest.json"); + fs.writeFileSync(file, JSON.stringify(configuration)); + const report = path.join(directory, "results.json"); + const log = path.join(directory, "jest.log"); + fs.rmSync(report, { force: true }); + const fd = fs.openSync(log, "w"); + return new Promise((resolve, reject) => { + const child = spawn( + process.execPath, + [ + require.resolve("jest/bin/jest"), + "--config", + file, + "--runInBand", + "--no-cache", + "--json", + "--outputFile", + report, + ], + { + cwd: root, + stdio: ["ignore", fd, fd], + env: { ...process.env, FORCE_COLOR: "0", CI: "true" }, + }, + ); fs.closeSync(fd); - const timer = setTimeout(() => child.kill('SIGKILL'), 30000); - child.on('error', error => {clearTimeout(timer);reject(error);}); - child.on('close', (status,signal) => { + const timer = setTimeout(() => child.kill("SIGKILL"), 30000); + child.on("error", (error) => { clearTimeout(timer); - const output = fs.readFileSync(log,'utf8'); - if (signal || !fs.existsSync(report)) return reject(new Error('Jest did not complete: '+signal+'\n'+output)); - resolve({status,output,report:JSON.parse(fs.readFileSync(report,'utf8'))}); + reject(error); + }); + child.on("close", (status, signal) => { + clearTimeout(timer); + const output = fs.readFileSync(log, "utf8"); + if (signal || !fs.existsSync(report)) + return reject( + new Error("Jest did not complete: " + signal + "\n" + output), + ); + resolve({ + status, + output, + report: JSON.parse(fs.readFileSync(report, "utf8")), + }); }); }); } async function main() { -try { - const control = await run(config); - if (control.status !== 0 || control.report.numPassedTests === 0) throw new Error('Unmodified control failed:\n'+control.output); - for (const [name,before,after] of faults) { - if (!source.includes(before)) throw new Error('Mutation no longer matches source: '+name); - const mutant = path.join(directory,'prepareConversion.js'); - fs.writeFileSync(mutant,source.replace(before,after)); - const result = await run({...config,moduleNameMapper:{'^\\./prepareConversion$':mutant}}); - if (result.status === 0 || result.report.numFailedTests === 0) { - throw new Error('Mutation survived or failed without a behavioral assertion: '+name+'\n'+result.output); + try { + const control = await run(config); + if (control.status !== 0 || control.report.numPassedTests === 0) + throw new Error("Unmodified control failed:\n" + control.output); + for (const [name, before, after] of faults) { + if (!source.includes(before)) + throw new Error("Mutation no longer matches source: " + name); + const mutant = path.join(directory, "prepareConversion.js"); + fs.writeFileSync(mutant, source.replace(before, after)); + const result = await run({ + ...config, + moduleNameMapper: { "^\\./prepareConversion$": mutant }, + }); + if (result.status === 0 || result.report.numFailedTests === 0) { + throw new Error( + "Mutation survived or failed without a behavioral assertion: " + + name + + "\n" + + result.output, + ); + } + process.stdout.write("Detected: " + name + "\n"); } - process.stdout.write('Detected: '+name+'\n'); + process.stdout.write( + faults.length + " / " + faults.length + " targeted mutations detected.\n", + ); + } finally { + fs.rmSync(directory, { recursive: true, force: true }); } - process.stdout.write(faults.length+' / '+faults.length+' targeted mutations detected.\n'); -} finally {fs.rmSync(directory,{recursive:true,force:true});} - } -main().catch(error=>{console.error(error);process.exitCode=1;}); +main().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/packages/rescript-relay/src/prepareConversion.js b/packages/rescript-relay/src/prepareConversion.js index 574aac68..fb92a177 100644 --- a/packages/rescript-relay/src/prepareConversion.js +++ b/packages/rescript-relay/src/prepareConversion.js @@ -180,7 +180,12 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { nullable === null ? (value) => (children[value.__typename] || any)(union(value)) : (value) => union((children[value.__typename] || any)(value)); - } else convert = record(children, node.fragments === true); + } else { + convert = + names.length === 0 && !node.fragments + ? any + : record(children, node.fragments === true); + } } convert = optional(convert); for (let i = 0; i < depth; i++) convert = optional(arrayOf(convert)); From 6bdf6612d8226667680ce99e87c7cb690369826a Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 09:08:26 +0200 Subject: [PATCH 06/23] Reduce generated bundle overhead and enforce conversion size budgets --- .github/workflows/bindings.yml | 3 + packages/relay | 2 +- .../GroupAvatar_group_graphql.res | 14 +- .../HasNameComponent_hasName_graphql.res | 14 +- ...alUser____relay_model_instance_graphql.res | 14 +- .../__generated__/LocalUser__id_graphql.res | 14 +- .../RichContent_content_graphql.res | 14 +- .../TestAliasedFragmentsQuery_graphql.res | 42 +- ...AliasedFragments_userFirstName_graphql.res | 14 +- ...tAliasedFragments_userLastName_graphql.res | 14 +- ...ayUnderlyingScalarSiblingQuery_graphql.res | 18 +- ...TestCatchLoggedInUserPropQuery_graphql.res | 26 +- ...TestCatchMemberPropNestedQuery_graphql.res | 26 +- .../TestCatchMemberPropQuery_graphql.res | 26 +- .../TestCatchMembersPropQuery_graphql.res | 26 +- .../TestCatchUnionMemberQuery_graphql.res | 26 +- .../TestCatchUnionMember_member_graphql.res | 6 +- .../TestCatchUser_user_graphql.res | 6 +- .../TestCodesplitQuery_graphql.res | 42 +- ...CompileInterfacesFragment_user_graphql.res | 14 +- .../TestConnections2_user_graphql.res | 6 +- .../TestConnections3_user_graphql.res | 6 +- .../TestConnectionsQuery_graphql.res | 18 +- ...tConnections_AddFriendMutation_graphql.res | 34 +- .../TestConnections_user_graphql.res | 6 +- .../TestConversionPlanQuery_graphql.res | 18 +- ...larAfterCustomScalarArrayQuery_graphql.res | 26 +- .../TestCustomScalarsQuery_graphql.res | 18 +- .../TestFragmentQuery_graphql.res | 26 +- ...estFragmentRequiredPlural_user_graphql.res | 14 +- .../TestFragmentRequiredQuery_graphql.res | 26 +- .../TestFragmentRequired_user_graphql.res | 14 +- .../TestFragment_allowUnsafeEnum_graphql.res | 14 +- .../TestFragment_inline_graphql.res | 14 +- .../TestFragment_plural_user_graphql.res | 14 +- .../TestFragment_sub_user_graphql.res | 14 +- .../TestFragment_user_graphql.res | 6 +- .../TestInputUnionQuery_graphql.res | 34 +- .../TestLocalPayloadQuery_graphql.res | 38 +- ...alPayloadViaNodeInterfaceQuery_graphql.res | 38 +- .../TestLocalPayload_user_graphql.res | 6 +- ...singFieldHandlersLinkedMeQuery_graphql.res | 42 +- ...issingFieldHandlersLinkedQuery_graphql.res | 26 +- ...ieldHandlersPluralBestiesQuery_graphql.res | 26 +- ...issingFieldHandlersPluralQuery_graphql.res | 26 +- ...singFieldHandlersScalarMeQuery_graphql.res | 42 +- ...issingFieldHandlersScalarQuery_graphql.res | 26 +- .../TestMutationInline_user_graphql.res | 14 +- ...tMutationProvidedVariable_user_graphql.res | 14 +- .../TestMutationQuery_graphql.res | 26 +- ...SetOnlineStatusComplexMutation_graphql.res | 34 +- ...utationSetOnlineStatusMutation_graphql.res | 54 +- ...ragmentSetOnlineStatusMutation_graphql.res | 54 +- ...ragmentSetOnlineStatusMutation_graphql.res | 38 +- ...ovidedVariableFragmentMutation_graphql.res | 26 +- .../TestMutation_user_graphql.res | 6 +- ...deInterfaceOnAbstractTypeQuery_graphql.res | 26 +- .../TestNodeInterfaceQuery_graphql.res | 26 +- .../TestNodeInterface_user_graphql.res | 14 +- .../TestNonReactQuery_graphql.res | 26 +- .../TestNonReact_user_graphql.res | 14 +- ...arsAfterCustomScalarArrayQuery_graphql.res | 26 +- .../TestNullableVariablesMutation_graphql.res | 34 +- .../TestNullableVariablesQuery_graphql.res | 42 +- .../TestObserverQuery_graphql.res | 42 +- .../TestPaginationInNodeQuery_graphql.res | 26 +- ...stPaginationInNodeRefetchQuery_graphql.res | 18 +- .../TestPaginationInNode_query_graphql.res | 6 +- .../TestPaginationInNode_user_graphql.res | 14 +- .../TestPaginationUnionQuery_graphql.res | 26 +- ...estPaginationUnionRefetchQuery_graphql.res | 18 +- .../TestPaginationUnion_query_graphql.res | 6 +- .../TestPaginationUnion_user_graphql.res | 14 +- ...estParseCustomScalarArrayQuery_graphql.res | 26 +- ...estPrefetchablePaginationQuery_graphql.res | 26 +- ...etchablePaginationRefetchQuery_graphql.res | 26 +- ...etchablePagination_user__edges_graphql.res | 14 +- ...estPrefetchablePagination_user_graphql.res | 6 +- .../TestProvidedVariablesQuery_graphql.res | 18 +- .../TestProvidedVariables_user_graphql.res | 14 +- .../TestQueryInputObjectsQuery_graphql.res | 34 +- .../__generated__/TestQuery_graphql.res | 26 +- .../TestRefetchingInNodeQuery_graphql.res | 18 +- ...stRefetchingInNodeRefetchQuery_graphql.res | 18 +- .../TestRefetchingInNode_user_graphql.res | 14 +- ...stRefetchingNoArgsRefetchQuery_graphql.res | 26 +- .../TestRefetchingNoArgs_query_graphql.res | 14 +- .../TestRefetchingQuery_graphql.res | 18 +- ...tchingRecordNoArgsRefetchQuery_graphql.res | 26 +- ...stRefetchingRecordNoArgs_query_graphql.res | 14 +- .../TestRefetchingRecordQuery_graphql.res | 18 +- ...stRefetchingRecordRefetchQuery_graphql.res | 18 +- .../TestRefetchingRecord_user_graphql.res | 6 +- .../TestRefetchingRefetchQuery_graphql.res | 18 +- .../TestRefetching_user_graphql.res | 6 +- .../TestRelayResolversAllQuery_graphql.res | 42 +- .../TestRelayResolversQuery_graphql.res | 26 +- .../TestRelayResolvers_user_graphql.res | 14 +- .../TestRelayUserResolver2_graphql.res | 14 +- .../TestRelayUserResolver_graphql.res | 14 +- .../TestRequiredFieldLoggerQuery_graphql.res | 42 +- ...alizeCustomScalarArrayMutation_graphql.res | 34 +- ...eMultipleCustomScalarsMutation_graphql.res | 34 +- ...scriptionProvidedVariable_user_graphql.res | 14 +- .../TestSubscriptionQuery_graphql.res | 26 +- ...riptionUserUpdatedSubscription_graphql.res | 20 +- ...edVariableFragmentSubscription_graphql.res | 20 +- .../TestSubscription_user_graphql.res | 14 +- .../TestTestingHelpersQuery_graphql.res | 54 +- ...TestTestingHelpers_plural_user_graphql.res | 14 +- .../TestTestingHelpers_sub_user_graphql.res | 14 +- .../TestTestingHelpers_user_graphql.res | 6 +- .../TestUnionFragmentQuery_graphql.res | 26 +- .../TestUnionFragmentUser_user_graphql.res | 14 +- .../TestUnionFragment_member_graphql.res | 6 +- ...estUnionFragment_plural_member_graphql.res | 6 +- .../__generated__/TestUnionsQuery_graphql.res | 26 +- .../TestUpdatableFragmentsQuery_graphql.res | 26 +- .../TestUpdatableFragments_query_graphql.res | 6 +- ...tUpdatableQuery_UpdatableQuery_graphql.res | 14 +- .../TestUpdatableQuery_graphql.res | 42 +- .../__generated__/UserAvatar_user_graphql.res | 14 +- ...erMeta____relay_model_instance_graphql.res | 14 +- .../__generated__/UserName_user_graphql.res | 14 +- .../__tests__/utils-module-tests.js | 1 + .../__tests__/utils-prepared-tests.js | 36 + ...dedQueryProvidedVariables_user_graphql.res | 14 +- .../TestPreloadedQuery_graphql.res | 18 +- ...TestPreloadedQuery_preloadable_graphql.res | 6 +- packages/rescript-relay/benchmarks/README.md | 3 + packages/rescript-relay/benchmarks/SIZE.md | 83 ++ .../rescript-relay/benchmarks/conversion.js | 22 +- .../benchmarks/results/size-before.json | 792 ++++++++++++++++++ .../benchmarks/results/size-current.json | 792 ++++++++++++++++++ .../benchmarks/results/size-original.json | 792 ++++++++++++++++++ .../benchmarks/results/size-runtime.json | 21 + .../benchmarks/size-budgets.json | 12 + .../benchmarks/size-fixtures.json | 131 +++ packages/rescript-relay/package.json | 18 +- .../scripts/build-conversion-modules.js | 6 +- .../scripts/measure-conversion-size.js | 133 +++ packages/rescript-relay/src/RescriptRelay.res | 3 + .../rescript-relay/src/RescriptRelay.resi | 3 + .../rescript-relay/src/prepareConversion.js | 10 +- packages/rescript-relay/src/utils.js | 12 +- packages/rescript-relay/yarn.lock | 162 ++++ 146 files changed, 3586 insertions(+), 2081 deletions(-) create mode 100644 packages/rescript-relay/benchmarks/SIZE.md create mode 100644 packages/rescript-relay/benchmarks/results/size-before.json create mode 100644 packages/rescript-relay/benchmarks/results/size-current.json create mode 100644 packages/rescript-relay/benchmarks/results/size-original.json create mode 100644 packages/rescript-relay/benchmarks/results/size-runtime.json create mode 100644 packages/rescript-relay/benchmarks/size-budgets.json create mode 100644 packages/rescript-relay/benchmarks/size-fixtures.json create mode 100644 packages/rescript-relay/scripts/measure-conversion-size.js diff --git a/.github/workflows/bindings.yml b/.github/workflows/bindings.yml index a106ad0f..cf4107e5 100644 --- a/.github/workflows/bindings.yml +++ b/.github/workflows/bindings.yml @@ -44,6 +44,8 @@ jobs: ENABLE_PERSISTING=true yarn test:ci yarn test:conversion yarn test:conversion:mutations + - name: Generated conversion size budget + run: yarn size:conversion --check --output conversion-size.json - name: Conversion benchmark (informational) run: yarn bench:conversion:prepared --samples 7 --duration 20 --output conversion-benchmark.json - uses: actions/upload-artifact@v4 @@ -51,4 +53,5 @@ jobs: name: conversion-performance path: | packages/rescript-relay/conversion-benchmark.json + packages/rescript-relay/conversion-size.json packages/rescript-relay/coverage/conversion/ diff --git a/packages/relay b/packages/relay index 6cdc0680..8abad4d1 160000 --- a/packages/relay +++ b/packages/relay @@ -1 +1 @@ -Subproject commit 6cdc068080bc85a01ec88cd6a556f33551212b3f +Subproject commit 8abad4d19429615a7d1bfd819c4c14e64fe55862 diff --git a/packages/rescript-relay/__tests__/__generated__/GroupAvatar_group_graphql.res b/packages/rescript-relay/__tests__/__generated__/GroupAvatar_group_graphql.res index f63c1c69..b8741586 100644 --- a/packages/rescript-relay/__tests__/__generated__/GroupAvatar_group_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/GroupAvatar_group_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/HasNameComponent_hasName_graphql.res b/packages/rescript-relay/__tests__/__generated__/HasNameComponent_hasName_graphql.res index c829d3d8..53fa011e 100644 --- a/packages/rescript-relay/__tests__/__generated__/HasNameComponent_hasName_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/HasNameComponent_hasName_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/LocalUser____relay_model_instance_graphql.res b/packages/rescript-relay/__tests__/__generated__/LocalUser____relay_model_instance_graphql.res index bc87cdfa..cd14f814 100644 --- a/packages/rescript-relay/__tests__/__generated__/LocalUser____relay_model_instance_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/LocalUser____relay_model_instance_graphql.res @@ -11,19 +11,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/LocalUser__id_graphql.res b/packages/rescript-relay/__tests__/__generated__/LocalUser__id_graphql.res index 78b9d916..6d3f848a 100644 --- a/packages/rescript-relay/__tests__/__generated__/LocalUser__id_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/LocalUser__id_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/RichContent_content_graphql.res b/packages/rescript-relay/__tests__/__generated__/RichContent_content_graphql.res index 9388c973..3026b802 100644 --- a/packages/rescript-relay/__tests__/__generated__/RichContent_content_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/RichContent_content_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res index 9665456b..66f7b35d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res @@ -34,51 +34,15 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res index 7ebd9389..7c4ceb21 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res index e9ec2b37..d1eb3b7d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res index bbf4e10b..43dfce82 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res @@ -39,10 +39,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["aaNumber"],"scalar":"TestsUtils.Number"},{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["aaNumber"],"scalar":"TestsUtils.Number"},{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.Number": TestsUtils.Number.serialize, @@ -54,14 +53,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friends"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friends"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -70,14 +69,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friends"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -86,6 +85,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res index 5be1a69b..a1359455 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res @@ -26,25 +26,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"path":["loggedInUser","createdAt","value"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"path":["loggedInUser","createdAt","value"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) @live let wrapResponseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -55,14 +42,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"path":["loggedInUser","createdAt","value"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, @@ -73,6 +60,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res index 65705566..f774d78b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res @@ -47,25 +47,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["member"],"union":"response_member"},{"path":["member","User","memberOfSingular","value"],"union":"response_member_User_memberOfSingular_value"},{"path":["member","User","memberOfSingular","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member"],"union":"response_member"},{"path":["member","User","memberOfSingular","value"],"union":"response_member_User_memberOfSingular_value"},{"path":["member","User","memberOfSingular","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) @live let wrapResponseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -78,14 +65,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["member"],"union":"response_member"},{"path":["member","User","memberOfSingular","value"],"union":"response_member_User_memberOfSingular_value"},{"path":["member","User","memberOfSingular","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, @@ -98,6 +85,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res index 4ac3e35d..3f082f78 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res @@ -34,25 +34,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["member","value"],"union":"response_member_value"},{"path":["member","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member","value"],"union":"response_member_value"},{"path":["member","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) @live let wrapResponseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -64,14 +51,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["member","value"],"union":"response_member_value"},{"path":["member","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, @@ -83,6 +70,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res index f7bd5e8b..9ef52d6b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res @@ -40,25 +40,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node","value"],"union":"response_members_edges_node_value"},{"path":["members","edges","node","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node","value"],"union":"response_members_edges_node_value"},{"path":["members","edges","node","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) @live let wrapResponseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -70,14 +57,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node","value"],"union":"response_members_edges_node_value"},{"path":["members","edges","node","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, @@ -89,6 +76,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res index e6fd657f..ea89086a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res @@ -25,25 +25,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -52,14 +39,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -68,6 +55,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res index 0a9f1967..b0b56d04 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res @@ -29,10 +29,9 @@ let wrap_fragment_t: Types.fragment_t => Types.fragment_t = RescriptRelay_Intern module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["value"],"union":"fragment_t"},{"path":["value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value"],"union":"fragment_t"},{"path":["value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) @live let fragmentConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, @@ -44,6 +43,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res index 0da46b47..7c470874 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res @@ -13,10 +13,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["value","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) @live let fragmentConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, @@ -27,6 +26,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestCodesplitQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCodesplitQuery_graphql.res index 430eaa1a..bc2ac362 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCodesplitQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCodesplitQuery_graphql.res @@ -48,51 +48,15 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.res index 1f2fff20..f596ef48 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res index 5a811aac..c8bc6cc3 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res @@ -33,10 +33,9 @@ let wrap_fragment_member: Types.fragment_member => Types.fragment_member = Rescr module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["member"],"union":"fragment_member"},{"list":1,"path":["member","User","friendsConnection","edges"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member"],"union":"fragment_member"},{"list":1,"path":["member","User","friendsConnection","edges"]}]},"version":2}`) @live let fragmentConverterMap = { "fragment_member": unwrap_fragment_member, @@ -47,6 +46,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res index 9fcb59cd..ead10032 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res @@ -24,10 +24,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friendsConnection","edges"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friendsConnection","edges"]}]},"version":2}`) @live let fragmentConverterMap = () @live @@ -36,6 +35,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res index 2ed5b6f6..52e27f6c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res @@ -32,10 +32,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -46,14 +45,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -62,14 +61,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -78,6 +77,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res index 49744f2e..77729902 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res @@ -26,10 +26,9 @@ module Types = { } module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["connections"]}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["connections"]}]},"version":2}`) @live let variablesConverterMap = () @live @@ -38,40 +37,17 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res index e975830d..e10b6bfe 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res @@ -22,10 +22,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["friendsConnection","edges"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsConnection","edges"]}]},"version":2}`) @live let fragmentConverterMap = () @live @@ -34,6 +33,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res index a37f9e88..6628828e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res @@ -40,10 +40,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["input"],"reference":"conversionContractInput"}],"conversionContractInput":[{"list":1,"path":["children"],"reference":"conversionContractInput"},{"list":2,"path":["grid"],"scalar":"TestsUtils.ConversionNumber"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"conversionContractInput"}],"conversionContractInput":[{"list":1,"path":["children"],"reference":"conversionContractInput"},{"list":2,"path":["grid"],"scalar":"TestsUtils.ConversionNumber"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.ConversionNumber": TestsUtils.ConversionNumber.serialize, @@ -54,14 +53,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["conversionContract","a","b"],"scalar":"TestsUtils.Datetime"},{"path":["conversionContract","a_b"],"scalar":"TestsUtils.ConversionNumber"},{"list":1,"path":["conversionContract","dates"],"scalar":"TestsUtils.Datetime"},{"list":2,"path":["conversionContract","grid"],"scalar":"TestsUtils.ConversionNumber"},{"list":2,"opaque":true,"path":["conversionContract","raw"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["conversionContract","a","b"],"scalar":"TestsUtils.Datetime"},{"path":["conversionContract","a_b"],"scalar":"TestsUtils.ConversionNumber"},{"list":1,"path":["conversionContract","dates"],"scalar":"TestsUtils.Datetime"},{"list":2,"path":["conversionContract","grid"],"scalar":"TestsUtils.ConversionNumber"},{"list":2,"opaque":true,"path":["conversionContract","raw"]}]},"version":2}`) @live let wrapResponseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -73,14 +72,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["conversionContract","a","b"],"scalar":"TestsUtils.Datetime"},{"path":["conversionContract","a_b"],"scalar":"TestsUtils.ConversionNumber"},{"list":1,"path":["conversionContract","dates"],"scalar":"TestsUtils.Datetime"},{"list":2,"path":["conversionContract","grid"],"scalar":"TestsUtils.ConversionNumber"},{"list":2,"opaque":true,"path":["conversionContract","raw"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, @@ -92,6 +91,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res index ddd38a18..fc227326 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res @@ -25,25 +25,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}`) @live let wrapResponseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -55,14 +42,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, @@ -74,6 +61,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res index 6d4ffb90..8ca73558 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res @@ -53,10 +53,9 @@ let wrap_response_member: Types.response_member => Types.response_member = Rescr type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -68,14 +67,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","friends"]},{"path":["loggedInUser","friends","createdAt"],"scalar":"TestsUtils.Datetime"},{"path":["member"],"union":"response_member"},{"path":["member","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","friends"]},{"path":["loggedInUser","friends","createdAt"],"scalar":"TestsUtils.Datetime"},{"path":["member"],"union":"response_member"},{"path":["member","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) @live let wrapResponseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -87,14 +86,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","friends"]},{"path":["loggedInUser","friends","createdAt"],"scalar":"TestsUtils.Datetime"},{"path":["member"],"union":"response_member"},{"path":["member","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.parse, @@ -106,6 +105,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res index d789a6b3..63fa8d47 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res @@ -36,25 +36,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -63,14 +50,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -79,6 +66,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.res index a744e8ba..cb107790 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res index b3541c7b..28839394 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res @@ -35,25 +35,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -62,14 +49,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -78,6 +65,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequired_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequired_user_graphql.res index 22de3485..9978edac 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequired_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequired_user_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.res index b6e06932..f9570c16 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_inline_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_inline_graphql.res index 580d3d0e..440a4dc1 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_inline_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_inline_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_plural_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_plural_user_graphql.res index 9c12319d..5d399f3e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_plural_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_plural_user_graphql.res @@ -16,19 +16,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_sub_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_sub_user_graphql.res index 94bc2eec..1580a441 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_sub_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_sub_user_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res index 6f3b4c60..e975fdf5 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res @@ -15,10 +15,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live let fragmentConverterMap = () @live @@ -27,6 +26,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res index 12dbe9ef..b8b12e8e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res @@ -32,10 +32,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["location"],"reference":"location"}],"byAddress":[],"byLoc":[],"location":[{"path":["byAddress"],"reference":"byAddress"},{"path":["byLoc"],"reference":"byLoc"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["location"],"reference":"location"}],"byAddress":[],"byLoc":[],"location":[{"path":["byAddress"],"reference":"byAddress"},{"path":["byLoc"],"reference":"byLoc"}]},"version":2}`) @live let variablesConverterMap = () @live @@ -44,40 +43,17 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res index b1a24eae..3d0a0270 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res @@ -93,25 +93,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -120,14 +107,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -136,14 +123,14 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) @live type wrapRawResponseRaw + %%private( @live - let wrapRawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","memberOf"],"union":"rawResponse_loggedInUser_memberOf"},{"path":["loggedInUser","memberOf","Group","topMember"],"union":"rawResponse_loggedInUser_memberOf_Group_topMember"},{"path":["loggedInUser","memberOfSingular"],"union":"rawResponse_loggedInUser_memberOfSingular"}]},"version":2}` - ) + let wrapRawResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","memberOf"],"union":"rawResponse_loggedInUser_memberOf"},{"path":["loggedInUser","memberOf","Group","topMember"],"union":"rawResponse_loggedInUser_memberOf_Group_topMember"},{"path":["loggedInUser","memberOfSingular"],"union":"rawResponse_loggedInUser_memberOfSingular"}]},"version":2}`) @live let wrapRawResponseConverterMap = { "rawResponse_loggedInUser_memberOf_Group_topMember": wrap_rawResponse_loggedInUser_memberOf_Group_topMember, @@ -156,14 +143,14 @@ module Internal = { wrapRawResponseConverterMap, null ) + ) @live let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) @live type rawResponseRaw + %%private( @live - let rawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","memberOf"],"union":"rawResponse_loggedInUser_memberOf"},{"path":["loggedInUser","memberOf","Group","topMember"],"union":"rawResponse_loggedInUser_memberOf_Group_topMember"},{"path":["loggedInUser","memberOfSingular"],"union":"rawResponse_loggedInUser_memberOfSingular"}]},"version":2}` - ) + let rawResponseConverter = wrapRawResponseConverter @live let rawResponseConverterMap = { "rawResponse_loggedInUser_memberOf_Group_topMember": unwrap_rawResponse_loggedInUser_memberOf_Group_topMember, @@ -176,6 +163,7 @@ module Internal = { rawResponseConverterMap, None ) + ) @live let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) type rawPreloadToken<'response> = {source: Nullable.t>} diff --git a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res index ac74cd3c..31714d80 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res @@ -118,25 +118,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}`) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, @@ -147,14 +134,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "response_node": unwrap_response_node, @@ -165,14 +152,14 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) @live type wrapRawResponseRaw + %%private( @live - let wrapRawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"rawResponse_node"},{"list":1,"path":["node","User","memberOf"],"union":"rawResponse_node_User_memberOf"},{"path":["node","User","memberOf","Group","topMember"],"union":"rawResponse_node_User_memberOf_Group_topMember"},{"path":["node","User","memberOfSingular"],"union":"rawResponse_node_User_memberOfSingular"}]},"version":2}` - ) + let wrapRawResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"rawResponse_node"},{"list":1,"path":["node","User","memberOf"],"union":"rawResponse_node_User_memberOf"},{"path":["node","User","memberOf","Group","topMember"],"union":"rawResponse_node_User_memberOf_Group_topMember"},{"path":["node","User","memberOfSingular"],"union":"rawResponse_node_User_memberOfSingular"}]},"version":2}`) @live let wrapRawResponseConverterMap = { "rawResponse_node_User_memberOf_Group_topMember": wrap_rawResponse_node_User_memberOf_Group_topMember, @@ -186,14 +173,14 @@ module Internal = { wrapRawResponseConverterMap, null ) + ) @live let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) @live type rawResponseRaw + %%private( @live - let rawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"rawResponse_node"},{"list":1,"path":["node","User","memberOf"],"union":"rawResponse_node_User_memberOf"},{"path":["node","User","memberOf","Group","topMember"],"union":"rawResponse_node_User_memberOf_Group_topMember"},{"path":["node","User","memberOfSingular"],"union":"rawResponse_node_User_memberOfSingular"}]},"version":2}` - ) + let rawResponseConverter = wrapRawResponseConverter @live let rawResponseConverterMap = { "rawResponse_node_User_memberOf_Group_topMember": unwrap_rawResponse_node_User_memberOf_Group_topMember, @@ -207,6 +194,7 @@ module Internal = { rawResponseConverterMap, None ) + ) @live let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) type rawPreloadToken<'response> = {source: Nullable.t>} diff --git a/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res index 48086e45..04aa4c3c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res @@ -63,10 +63,9 @@ let wrap_fragment_memberOfSingular: Types.fragment_memberOfSingular => Types.fra module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"fragment_memberOf"},{"path":["memberOf","Group","topMember"],"union":"fragment_memberOf_Group_topMember"},{"path":["memberOfSingular"],"union":"fragment_memberOfSingular"}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"fragment_memberOf"},{"path":["memberOf","Group","topMember"],"union":"fragment_memberOf_Group_topMember"},{"path":["memberOfSingular"],"union":"fragment_memberOfSingular"}]},"version":2}`) @live let fragmentConverterMap = { "fragment_memberOf_Group_topMember": unwrap_fragment_memberOf_Group_topMember, @@ -79,6 +78,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.res index f277883b..b535ba4b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.res @@ -24,51 +24,15 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res index 2a100177..167c81ae 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res @@ -33,25 +33,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}`) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, @@ -62,14 +49,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "response_node": unwrap_response_node, @@ -80,6 +67,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res index 5fcd7aa2..a9237efa 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res @@ -24,25 +24,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["onlineBesties"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["onlineBesties"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -51,14 +38,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["onlineBesties"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -67,6 +54,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res index 1948f976..8cf169e7 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res @@ -24,25 +24,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["topOnlineUserList"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["topOnlineUserList"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -51,14 +38,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["topOnlineUserList"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -67,6 +54,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.res index c347a1c0..23c4c688 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.res @@ -24,51 +24,15 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res index d17f53c1..84e3752c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res @@ -33,25 +33,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}`) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, @@ -62,14 +49,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "response_node": unwrap_response_node, @@ -80,6 +67,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationInline_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationInline_user_graphql.res index c88250a5..f1b8f229 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationInline_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationInline_user_graphql.res @@ -16,19 +16,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationProvidedVariable_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationProvidedVariable_user_graphql.res index d63d306c..549f3e72 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationProvidedVariable_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationProvidedVariable_user_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res index 13cfd6b2..e93faae8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res @@ -24,25 +24,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -51,14 +38,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -67,6 +54,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res index c9c675bd..fd3b176f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res @@ -28,10 +28,9 @@ module Types = { } module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["input"],"reference":"setOnlineStatusInput"}],"recursiveSetOnlineStatusInput":[{"path":["setOnlineStatus"],"reference":"setOnlineStatusInput"},{"path":["someValue"],"scalar":"TestsUtils.IntString"}],"setOnlineStatusInput":[{"path":["recursed"],"reference":"recursiveSetOnlineStatusInput"},{"opaque":true,"path":["someJsonValue"]}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"setOnlineStatusInput"}],"recursiveSetOnlineStatusInput":[{"path":["setOnlineStatus"],"reference":"setOnlineStatusInput"},{"path":["someValue"],"scalar":"TestsUtils.IntString"}],"setOnlineStatusInput":[{"path":["recursed"],"reference":"recursiveSetOnlineStatusInput"},{"opaque":true,"path":["someJsonValue"]}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, @@ -42,40 +41,17 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res index 8f5ffc53..b895427e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res @@ -42,25 +42,12 @@ module Types = { module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -69,14 +56,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -85,40 +72,17 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) @live type wrapRawResponseRaw @live - let wrapRawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapRawResponseConverterMap = () - @live - let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( - wrapRawResponseConverter, - wrapRawResponseConverterMap, - null - ) - @live - let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) + let convertWrapRawResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type rawResponseRaw @live - let rawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let rawResponseConverterMap = () - @live - let preparedRawResponseConverter = RescriptRelay.prepareConversion( - rawResponseConverter, - rawResponseConverterMap, - None - ) - @live - let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) + let convertRawResponse = value => RescriptRelay.convertWithoutPlan(value, None) } module Utils = { @@warning("-33") diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res index 540f6f7a..c9438302 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res @@ -39,25 +39,12 @@ module Types = { module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -66,14 +53,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -82,40 +69,17 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) @live type wrapRawResponseRaw @live - let wrapRawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapRawResponseConverterMap = () - @live - let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( - wrapRawResponseConverter, - wrapRawResponseConverterMap, - null - ) - @live - let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) + let convertWrapRawResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type rawResponseRaw @live - let rawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let rawResponseConverterMap = () - @live - let preparedRawResponseConverter = RescriptRelay.prepareConversion( - rawResponseConverter, - rawResponseConverterMap, - None - ) - @live - let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) + let convertRawResponse = value => RescriptRelay.convertWithoutPlan(value, None) } module Utils = { @@warning("-33") diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res index 70877363..13f609ac 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res @@ -61,25 +61,12 @@ let unwrap_rawResponse_setOnlineStatus_user_memberOf: Types.rawResponse_setOnlin let wrap_rawResponse_setOnlineStatus_user_memberOf: Types.rawResponse_setOnlineStatus_user_memberOf => Types.rawResponse_setOnlineStatus_user_memberOf = RescriptRelay_Internal.wrapUnion module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -88,14 +75,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -104,14 +91,14 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) @live type wrapRawResponseRaw + %%private( @live - let wrapRawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["setOnlineStatus","user","memberOf"],"union":"rawResponse_setOnlineStatus_user_memberOf"}]},"version":2}` - ) + let wrapRawResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["setOnlineStatus","user","memberOf"],"union":"rawResponse_setOnlineStatus_user_memberOf"}]},"version":2}`) @live let wrapRawResponseConverterMap = { "rawResponse_setOnlineStatus_user_memberOf": wrap_rawResponse_setOnlineStatus_user_memberOf, @@ -122,14 +109,14 @@ module Internal = { wrapRawResponseConverterMap, null ) + ) @live let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) @live type rawResponseRaw + %%private( @live - let rawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["setOnlineStatus","user","memberOf"],"union":"rawResponse_setOnlineStatus_user_memberOf"}]},"version":2}` - ) + let rawResponseConverter = wrapRawResponseConverter @live let rawResponseConverterMap = { "rawResponse_setOnlineStatus_user_memberOf": unwrap_rawResponse_setOnlineStatus_user_memberOf, @@ -140,6 +127,7 @@ module Internal = { rawResponseConverterMap, None ) + ) @live let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res index a79edaed..0958ef3e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res @@ -24,25 +24,12 @@ module Types = { module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["updateUserAvatar","user"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["updateUserAvatar","user"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -51,14 +38,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["updateUserAvatar","user"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -67,6 +54,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res index 563f948c..9de582bd 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res @@ -33,10 +33,9 @@ let wrap_fragment_memberOf: Types.fragment_memberOf => Types.fragment_memberOf = module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"fragment_memberOf"}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"fragment_memberOf"}]},"version":2}`) @live let fragmentConverterMap = { "fragment_memberOf": unwrap_fragment_memberOf, @@ -47,6 +46,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res index 8b569331..321b1205 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res @@ -38,25 +38,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}`) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, @@ -67,14 +54,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "response_node": unwrap_response_node, @@ -85,6 +72,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res index 5ab00204..7e6321e6 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res @@ -50,25 +50,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["_testExhaustiveInterface"],"union":"response__testExhaustiveInterface"},{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["_testExhaustiveInterface"],"union":"response__testExhaustiveInterface"},{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}`) @live let wrapResponseConverterMap = { "response__testExhaustiveInterface": wrap_response__testExhaustiveInterface, @@ -80,14 +67,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["_testExhaustiveInterface"],"union":"response__testExhaustiveInterface"},{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "response__testExhaustiveInterface": unwrap_response__testExhaustiveInterface, @@ -99,6 +86,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestNodeInterface_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNodeInterface_user_graphql.res index 518f55ef..1f28a326 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNodeInterface_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNodeInterface_user_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res index b87cbb37..4cb0026c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res @@ -25,25 +25,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -52,14 +39,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -68,6 +55,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestNonReact_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNonReact_user_graphql.res index fe42f9ba..eb9f1b2d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNonReact_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNonReact_user_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res index b58f6059..af7078aa 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res @@ -29,25 +29,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}`) @live let wrapResponseConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, @@ -58,14 +45,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.parse, @@ -76,6 +63,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res index 8076f091..9da3b644 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res @@ -28,10 +28,9 @@ module Types = { } module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["someInput"],"reference":"someInput"}],"someInput":[{"path":["datetime"],"scalar":"TestsUtils.Datetime"},{"path":["recursive"],"reference":"someInput"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["someInput"],"reference":"someInput"}],"someInput":[{"path":["datetime"],"scalar":"TestsUtils.Datetime"},{"path":["recursive"],"reference":"someInput"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -42,40 +41,17 @@ module Internal = { variablesConverterMap, null ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesQuery_graphql.res index 666fe166..0f679c05 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesQuery_graphql.res @@ -24,51 +24,15 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestObserverQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestObserverQuery_graphql.res index 48c9b286..f24f9db7 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestObserverQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestObserverQuery_graphql.res @@ -24,51 +24,15 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res index 5dae7345..bd0cdba9 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res @@ -35,25 +35,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -62,14 +49,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -78,6 +65,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res index 43a306ff..0b3f5a9b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res @@ -47,10 +47,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}`) @live let variablesConverterMap = () @live @@ -59,14 +58,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -75,14 +74,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -91,6 +90,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res index 5ef97604..8c504bd9 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res @@ -23,10 +23,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["friendsConnection","edges"]},{"fragments":true,"path":["friendsConnection","edges","node"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsConnection","edges"]},{"fragments":true,"path":["friendsConnection","edges","node"]}]},"version":2}`) @live let fragmentConverterMap = () @live @@ -35,6 +34,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_user_graphql.res index bbe56248..69bcca99 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_user_graphql.res @@ -18,19 +18,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res index 1fe3cf65..51850cc2 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res @@ -30,25 +30,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -57,14 +44,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -73,6 +60,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res index 2a23ee5c..bcbb6737 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res @@ -42,10 +42,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}`) @live let variablesConverterMap = () @live @@ -54,14 +53,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -70,14 +69,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -86,6 +85,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res index 44781ea8..6fc54819 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res @@ -48,10 +48,9 @@ let wrap_fragment_members_edges_node: Types.fragment_members_edges_node => Types module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"fragment_members_edges_node"},{"list":1,"path":["members","edges","node","Group","adminsConnection","edges"]},{"fragments":true,"path":["members","edges","node","User"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"fragment_members_edges_node"},{"list":1,"path":["members","edges","node","Group","adminsConnection","edges"]},{"fragments":true,"path":["members","edges","node","User"]}]},"version":2}`) @live let fragmentConverterMap = { "fragment_members_edges_node": unwrap_fragment_members_edges_node, @@ -62,6 +61,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_user_graphql.res index e75b0399..3650655a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_user_graphql.res @@ -17,19 +17,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res index 15030967..ecde0227 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res @@ -27,25 +27,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["loggedInUser","intString"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","justStrings"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","intString"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","justStrings"]}]},"version":2}`) @live let wrapResponseConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, @@ -56,14 +43,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["loggedInUser","intString"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","justStrings"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.parse, @@ -74,6 +61,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res index 12a9b518..f4ae7328 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res @@ -24,25 +24,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -51,14 +38,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -67,6 +54,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res index 51a4096c..242da595 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res @@ -44,25 +44,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -71,14 +58,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -87,6 +74,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.res index 9373c95f..55d72e73 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.res @@ -19,19 +19,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res index 26b9dc3f..71d9527d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res @@ -24,10 +24,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"list":1,"path":["friendsConnection","edges"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"list":1,"path":["friendsConnection","edges"]}]},"version":2}`) @live let fragmentConverterMap = () @live @@ -36,6 +35,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res index 8b759c9b..7911f12c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res @@ -24,10 +24,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesIntStrArr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesIntStrArr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, @@ -38,14 +37,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -54,14 +53,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -70,6 +69,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariables_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariables_user_graphql.res index 554d0496..24e6d80f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariables_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariables_user_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res index f8cf1997..f371554a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res @@ -30,10 +30,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["input"],"reference":"searchInput"}],"searchInput":[{"list":1,"path":["names"]}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"searchInput"}],"searchInput":[{"list":1,"path":["names"]}]},"version":2}`) @live let variablesConverterMap = () @live @@ -42,40 +41,17 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res index fb33ee93..9d8559f2 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res @@ -41,25 +41,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["users","edges"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["users","edges"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -68,14 +55,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["users","edges"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -84,6 +71,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res index 95d1193b..b281ee61 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res @@ -45,10 +45,9 @@ let wrap_response_node: Types.response_node => Types.response_node = RescriptRel type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}`) @live let variablesConverterMap = () @live @@ -57,14 +56,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}`) @live let wrapResponseConverterMap = { "response_node": wrap_response_node, @@ -75,14 +74,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "response_node": unwrap_response_node, @@ -93,6 +92,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res index 6b6bc59a..b3ccde93 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res @@ -43,10 +43,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}`) @live let variablesConverterMap = () @live @@ -55,14 +54,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -71,14 +70,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -87,6 +86,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNode_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNode_user_graphql.res index 02118060..0064817d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNode_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNode_user_graphql.res @@ -19,19 +19,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res index 4633832c..78d59f6a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res @@ -22,25 +22,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -49,14 +36,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -65,6 +52,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgs_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgs_query_graphql.res index 9bb578c3..de972419 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgs_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgs_query_graphql.res @@ -16,19 +16,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res index 49c28001..cbcadd05 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res @@ -40,10 +40,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -55,14 +54,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -71,14 +70,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -87,6 +86,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res index 9ab4b5cd..573944f1 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res @@ -22,25 +22,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -49,14 +36,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -65,6 +52,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.res index 2db3e668..9c5496df 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.res @@ -16,19 +16,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res index fcf1f862..d01428dd 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res @@ -40,10 +40,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -55,14 +54,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -71,14 +70,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -87,6 +86,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res index 1e8f4847..aaa853b0 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res @@ -51,10 +51,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -66,14 +65,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -82,14 +81,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -98,6 +97,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res index bc6b3619..e7ece767 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res @@ -22,10 +22,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}`) @live let fragmentConverterMap = () @live @@ -34,6 +33,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res index 3c2c63c1..6934cf8b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res @@ -51,10 +51,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.Datetime": TestsUtils.Datetime.serialize, @@ -66,14 +65,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -82,14 +81,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -98,6 +97,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res index cf51c023..b2483d05 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res @@ -22,10 +22,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}`) @live let fragmentConverterMap = () @live @@ -34,6 +33,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversAllQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversAllQuery_graphql.res index 763ae8d4..43381f60 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversAllQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversAllQuery_graphql.res @@ -30,51 +30,15 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res index 4aa98997..3984d6ac 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res @@ -24,25 +24,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -51,14 +38,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -67,6 +54,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayResolvers_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayResolvers_user_graphql.res index 9e272876..b099c656 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayResolvers_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayResolvers_user_graphql.res @@ -15,19 +15,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver2_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver2_graphql.res index 229d09eb..14e22519 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver2_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver2_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver_graphql.res index d27ae59f..33b0f4d8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayUserResolver_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.res index fb86fc25..bc71c10d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.res @@ -24,51 +24,15 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res index 8c6224c4..20b4e246 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res @@ -21,10 +21,9 @@ module Types = { } module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["input"],"scalar":"TestsUtils.IntString"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["input"],"scalar":"TestsUtils.IntString"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, @@ -35,40 +34,17 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res index b389208d..43b2b5ee 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res @@ -18,10 +18,9 @@ module Types = { } module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["input"],"reference":"serializeMultipleCustomScalars"}],"serializeMultipleCustomScalars":[{"list":1,"path":["os1s"],"scalar":"TestsUtils.ObjectScalar1"},{"path":["os2"],"scalar":"TestsUtils.ObjectScalar2"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"serializeMultipleCustomScalars"}],"serializeMultipleCustomScalars":[{"list":1,"path":["os1s"],"scalar":"TestsUtils.ObjectScalar1"},{"path":["os2"],"scalar":"TestsUtils.ObjectScalar2"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.ObjectScalar1": TestsUtils.ObjectScalar1.serialize, @@ -33,40 +32,17 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.res index 0345d991..8d545503 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res index e2b8dd92..823b33b1 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res @@ -24,25 +24,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -51,14 +38,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -67,6 +54,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res index 40248408..3bd54b6b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res @@ -28,25 +28,12 @@ module Types = { module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["userUpdated","user"]}]},"version":2}` - ) + let responseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["userUpdated","user"]}]},"version":2}`) @live let responseConverterMap = () @live @@ -55,6 +42,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type rawResponseRaw = responseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res index bea8a22e..50d7ea2b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res @@ -26,25 +26,12 @@ module Types = { module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["userUpdated","user"]}]},"version":2}` - ) + let responseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["userUpdated","user"]}]},"version":2}`) @live let responseConverterMap = () @live @@ -53,6 +40,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type rawResponseRaw = responseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscription_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscription_user_graphql.res index efd4007a..92891735 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscription_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscription_user_graphql.res @@ -16,19 +16,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res index 55642c0d..ca6c8b9c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res @@ -37,25 +37,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -64,14 +51,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -80,40 +67,17 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) @live type wrapRawResponseRaw @live - let wrapRawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapRawResponseConverterMap = () - @live - let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( - wrapRawResponseConverter, - wrapRawResponseConverterMap, - null - ) - @live - let convertWrapRawResponse = value => RescriptRelay.runConversion(preparedWrapRawResponseConverter, value) + let convertWrapRawResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type rawResponseRaw @live - let rawResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let rawResponseConverterMap = () - @live - let preparedRawResponseConverter = RescriptRelay.prepareConversion( - rawResponseConverter, - rawResponseConverterMap, - None - ) - @live - let convertRawResponse = value => RescriptRelay.runConversion(preparedRawResponseConverter, value) + let convertRawResponse = value => RescriptRelay.convertWithoutPlan(value, None) type rawPreloadToken<'response> = {source: Nullable.t>} external tokenToRaw: queryRef => rawPreloadToken = "%identity" } diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_plural_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_plural_user_graphql.res index 68f05643..22f3ff7d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_plural_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_plural_user_graphql.res @@ -16,19 +16,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_sub_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_sub_user_graphql.res index 1e69bb90..7e77e73b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_sub_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_sub_user_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res index 78ca61bf..481326d5 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res @@ -15,10 +15,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live let fragmentConverterMap = () @live @@ -27,6 +26,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res index 66e14dd8..125eedbf 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res @@ -25,25 +25,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -52,14 +39,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -68,6 +55,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentUser_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentUser_user_graphql.res index 52aa100c..30835912 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentUser_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentUser_user_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res index 08c4ff23..fa338fb5 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res @@ -28,10 +28,9 @@ let wrap_fragment: Types.fragment => Types.fragment = RescriptRelay_Internal.wra module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":[],"union":"fragment"},{"fragments":true,"path":["User"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":[],"union":"fragment"},{"fragments":true,"path":["User"]}]},"version":2}`) @live let fragmentConverterMap = { "fragment": unwrap_fragment, @@ -42,6 +41,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res index 595072c1..2be7fb63 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res @@ -29,10 +29,9 @@ let wrap_fragment: Types.fragment => Types.fragment = RescriptRelay_Internal.wra module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":[],"union":"fragment"},{"fragments":true,"path":["User"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":[],"union":"fragment"},{"fragments":true,"path":["User"]}]},"version":2}`) @live let fragmentConverterMap = { "fragment": unwrap_fragment, @@ -43,6 +42,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res index 68fe16b5..ac53d839 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res @@ -70,25 +70,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"response_members_edges_node"},{"list":1,"path":["members","edges","node","Group","members"],"union":"response_members_edges_node_Group_members"}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"response_members_edges_node"},{"list":1,"path":["members","edges","node","Group","members"],"union":"response_members_edges_node_Group_members"}]},"version":2}`) @live let wrapResponseConverterMap = { "response_members_edges_node_Group_members": wrap_response_members_edges_node_Group_members, @@ -100,14 +87,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"response_members_edges_node"},{"list":1,"path":["members","edges","node","Group","members"],"union":"response_members_edges_node_Group_members"}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = { "response_members_edges_node_Group_members": unwrap_response_members_edges_node_Group_members, @@ -119,6 +106,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res index 91d3da5c..f2af8c68 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res @@ -25,25 +25,12 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -52,14 +39,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -68,6 +55,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res index 53c21260..cc0cf355 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res @@ -21,10 +21,9 @@ module Types = { module Internal = { @live type fragmentRaw + %%private( @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}` - ) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let fragmentConverterMap = () @live @@ -33,6 +32,7 @@ module Internal = { fragmentConverterMap, None ) + ) @live let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.res index 419c37eb..4db054c8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.res @@ -26,19 +26,7 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) } diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_graphql.res index dd70b482..c0f2a4c8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableQuery_graphql.res @@ -38,51 +38,15 @@ type queryRef module Internal = { @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let variablesConverterMap = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesConverterMap, - None - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let wrapResponseConverterMap = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseConverterMap, - null - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let responseConverterMap = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseConverterMap, - None - ) - @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/UserAvatar_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/UserAvatar_user_graphql.res index cd31c313..f3ce1402 100644 --- a/packages/rescript-relay/__tests__/__generated__/UserAvatar_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/UserAvatar_user_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/UserMeta____relay_model_instance_graphql.res b/packages/rescript-relay/__tests__/__generated__/UserMeta____relay_model_instance_graphql.res index d6f9538a..247c96da 100644 --- a/packages/rescript-relay/__tests__/__generated__/UserMeta____relay_model_instance_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/UserMeta____relay_model_instance_graphql.res @@ -11,19 +11,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/UserName_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/UserName_user_graphql.res index 54ec7c33..6780204d 100644 --- a/packages/rescript-relay/__tests__/__generated__/UserName_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/UserName_user_graphql.res @@ -14,19 +14,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/utils-module-tests.js b/packages/rescript-relay/__tests__/utils-module-tests.js index e5474ca2..55c5d2b5 100644 --- a/packages/rescript-relay/__tests__/utils-module-tests.js +++ b/packages/rescript-relay/__tests__/utils-module-tests.js @@ -29,6 +29,7 @@ test("release ESM and CommonJS exports execute the same legacy and prepared conv const expected={items:[1,nullable],after:nullable}; for(const module of [esm,cjs]) { assert.deepEqual(module.traverser(data,legacy,{scalar:Number},nullable),expected); + assert.deepEqual(module.convertWithoutPlan({value:null},nullable),{value:nullable}); assert.deepEqual(module.runConversion(module.prepareConversion(plan,{scalar:Number},nullable),data),expected); } } diff --git a/packages/rescript-relay/__tests__/utils-prepared-tests.js b/packages/rescript-relay/__tests__/utils-prepared-tests.js index c9396a38..42ed7fb3 100644 --- a/packages/rescript-relay/__tests__/utils-prepared-tests.js +++ b/packages/rescript-relay/__tests__/utils-prepared-tests.js @@ -562,3 +562,39 @@ test("native scalar list plans preserve primitives and normalize nullable member values: ["x", undefined, [undefined]], }); }); + +describe.each([null, undefined])( + "shared conversion without instructions (%s)", + (nullable) => { + test("matches ordinary preparation without retaining or mutating values", () => { + const { convertWithoutPlan } = require("../src/utils"); + const option = { BS_PRIVATE_NESTED_SOME_NONE: 0 }; + const metadata = { opaque: null }; + const input = freeze({ + list: [null, undefined, , { value: null }, option], + __metadata: metadata, + }); + const expected = { + list: [nullable, nullable, , { value: nullable }, option], + __metadata: metadata, + }; + expect(convertWithoutPlan(input, nullable)).toStrictEqual(expected); + expect(convertWithoutPlan(input, nullable)).toStrictEqual( + prepareConversion( + { version: 2, roots: { __root: [] } }, + {}, + nullable, + )(input), + ); + expect(convertWithoutPlan(null, nullable)).toBe(nullable); + expect(convertWithoutPlan([input], nullable)).toStrictEqual([expected]); + expect(convertWithoutPlan(option, nullable)).toBe(option); + const unchanged = freeze({ values: [0, false, "", nullable] }); + expect(convertWithoutPlan(unchanged, nullable)).toBe(unchanged); + const mutable = { value: null }; + convertWithoutPlan(mutable, nullable); + mutable.value = "updated"; + expect(convertWithoutPlan(mutable, nullable)).toBe(mutable); + }); + }, +); diff --git a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.res b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.res index 96e98d3d..791bb57d 100644 --- a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.res +++ b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.res @@ -13,19 +13,7 @@ module Internal = { @live type fragmentRaw @live - let fragmentConverter: JSON.t = %raw( - json`{"roots":{"__root":[]},"version":2}` - ) - @live - let fragmentConverterMap = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentConverterMap, - None - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res index 5029583a..cab3822c 100644 --- a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res +++ b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res @@ -47,10 +47,9 @@ module Types = { type queryRef module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, @@ -61,14 +60,14 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw + %%private( @live - let wrapResponseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]}]},"version":2}` - ) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]}]},"version":2}`) @live let wrapResponseConverterMap = () @live @@ -77,14 +76,14 @@ module Internal = { wrapResponseConverterMap, null ) + ) @live let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) @live type responseRaw + %%private( @live - let responseConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]}]},"version":2}` - ) + let responseConverter = wrapResponseConverter @live let responseConverterMap = () @live @@ -93,6 +92,7 @@ module Internal = { responseConverterMap, None ) + ) @live let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) type wrapRawResponseRaw = wrapResponseRaw diff --git a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res index 45f7d65e..760efaa3 100644 --- a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res +++ b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res @@ -13,10 +13,9 @@ module Types = { } module Internal = { + %%private( @live - let variablesConverter: JSON.t = %raw( - json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}` - ) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}`) @live let variablesConverterMap = { "TestsUtils.IntString": TestsUtils.IntString.serialize, @@ -27,6 +26,7 @@ module Internal = { variablesConverterMap, None ) + ) @live let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) } diff --git a/packages/rescript-relay/benchmarks/README.md b/packages/rescript-relay/benchmarks/README.md index c47c1c48..4b2b2af5 100644 --- a/packages/rescript-relay/benchmarks/README.md +++ b/packages/rescript-relay/benchmarks/README.md @@ -79,3 +79,6 @@ The existing bindings already memoize conversions with `useMemo` keyed by the Relay snapshot. The mounted regression tests verify unchanged rerenders reuse that result and store updates produce freshly converted data. No hook-level cache or dependency changes were needed. + +See [bundle-size measurements and budgets](SIZE.md) for complete generated JS, +shared/separate bundles, gzip/Brotli reports, and reproduction commands. diff --git a/packages/rescript-relay/benchmarks/SIZE.md b/packages/rescript-relay/benchmarks/SIZE.md new file mode 100644 index 00000000..7736246f --- /dev/null +++ b/packages/rescript-relay/benchmarks/SIZE.md @@ -0,0 +1,83 @@ +# Generated conversion bundle size + +This measures **complete compiled JavaScript artifacts**, including Relay nodes, +conversion metadata, helper functions, and initialization calls. It replaces the +earlier metadata-only gzip estimate. esbuild 0.25.12 bundles/minifies a fixed set +of 129 pre-existing artifacts; gzip uses level 9 and Brotli uses quality 11. + +Dependencies (React, Relay, bindings, custom scalar modules, and generated imports) +are external in every measurement. These are artifact-only bundles, **not a +production application build**. The combined case exports all artifacts in one +bundle. The separate case sums independently bundled/compressed artifacts. Real +code splitting and import usage will change the result. The shared runtime is +measured separately below and must not be counted once per artifact. + +| Version | One bundle, minified | One bundle, gzip | One bundle, Brotli | Separate bundles, gzip | Separate bundles, Brotli | +|---|---:|---:|---:|---:|---:| +| Original (`520cac4`) | 284,957 | 37,573 | 26,976 | 119,093 | 106,076 | +| First prepared redesign (`e856b90`) | 313,772 | 41,628 | 29,248 | 126,052 | 112,258 | +| After size optimization | 277,982 | 36,961 | 26,651 | 119,154 | 105,719 | + +All numbers are bytes. Relative to the first redesign, this saves 35,790 minified +bytes / 4,667 gzip bytes in the combined bundle, and 6,898 gzip bytes across the +separate bundles. Relative to the original, combined gzip is 612 bytes smaller; +separate gzip is 61 bytes larger. These totals do not promise that each individual +artifact shrinks; per-artifact sizes are included in the JSON reports. + +## Changes + +- Keep plans, callback maps, and prepared handles private, so the compiler does + not export them as properties of each `Internal` object. Conversion functions + remain available to the bindings. +- Share identical immutable plans within an artifact, including read/write + directions. Their callback maps and prepared converters remain independent. +- Emit a call to a shared generic converter when no instructions are needed. + This avoids allocating empty plans and preparing equivalent converters in each + generated module. The shared converter retains no application data or callbacks. + +The lossless, readable version 2 instruction format is unchanged. No minified +opcodes, dynamic code generation, global plan registry, or input memoization was +introduced. Nonempty prepared converters execute the same response traversal. + +## Reproduction and CI + +After building the PPX and compiling the bindings (`yarn build`), run: + +```sh +yarn size:conversion --check --output /tmp/conversion-size.json +``` + +To compare a compiled package in another checkout: + +```sh +yarn size:conversion --root /path/to/other/packages/rescript-relay --output /tmp/other-size.json +``` + +Both packages must use the same ReScript version and CommonJS output configuration. +For these reports, original artifacts came from `520cac4933c118a85cf0dffcd1a19a5dba34ad4f` +and the earlier redesign from `e856b90`; both were compiled with ReScript 12.3.0. +The measurement deliberately externalizes dependencies so the comparison isolates +compiler output. `size-fixtures.json` pins the identical set of selections, excluding +the new regression query and schema helper. Use separate worktrees or scratch +packages when compiling historical artifacts; do not overwrite current artifacts. + +Bindings CI checks minified, gzip, and Brotli budgets for both bundle layouts and +uploads the report. Budgets allow 2% headroom over this result. Intentional changes +to fixture coverage, esbuild version, or budgets need review. The raw reports are +`results/size-original.json`, `results/size-before.json`, and `results/size-current.json`. + +## Shared runtime + +This conservatively includes both prepared conversion and the legacy compatibility +export, bundled once. The original runtime is extracted from `520cac4`; the previous +prepared runtime is extracted from `e856b90`. + +| Runtime | Minified | Gzip | Brotli | +|---|---:|---:|---:| +| original | 2916 | 1144 | 1010 | +| before | 5605 | 2261 | 2041 | +| current | 5786 | 2330 | 2108 | + +The runtime remains larger than the original because it supports both protocols. +Shared nullable converters add a small fixed cost while removing per-artifact +initialization code. There is no measured full-app bundle result yet. diff --git a/packages/rescript-relay/benchmarks/conversion.js b/packages/rescript-relay/benchmarks/conversion.js index 83d3d9fb..c60bd644 100644 --- a/packages/rescript-relay/benchmarks/conversion.js +++ b/packages/rescript-relay/benchmarks/conversion.js @@ -12,7 +12,7 @@ const option = (name) => { return i < 0 ? undefined : args[i + 1]; }; const implementation = option("--implementation"); -const { traverser, prepareConversion } = require( +const { traverser, prepareConversion, convertWithoutPlan } = require( implementation ? path.resolve(implementation) : "../src/utils", ); const samples = Number(option("--samples") || 15); @@ -57,16 +57,24 @@ function batch(fixture, count) { } const results = cases.map((fixture) => { const before = v8.deserialize(v8.serialize(fixture.root)); - let preparationNs; - if (prepared) { + // Match generated artifacts: empty plans reuse the shared nullable converter. + const withoutPlan = + prepared && + convertWithoutPlan && + Object.keys(fixture.plan.roots).length === 1 && + fixture.plan.roots.__root.length === 0; + let preparationNs = withoutPlan ? 0 : undefined; + if (prepared && !withoutPlan) { const start = performance.now(); for (let i = 0; i < 1000; i++) sink = prepareConversion(fixture.plan, converters, fixture.nullable); preparationNs = ((performance.now() - start) * 1e6) / 1000; } - fixture.convert = prepared - ? prepareConversion(fixture.plan, converters, fixture.nullable) - : (value) => traverser(value, fixture.maps, converters, fixture.nullable); + fixture.convert = withoutPlan + ? (value) => convertWithoutPlan(value, fixture.nullable) + : prepared + ? prepareConversion(fixture.plan, converters, fixture.nullable) + : (value) => traverser(value, fixture.maps, converters, fixture.nullable); const converted = fixture.convert(fixture.root); assert.deepStrictEqual(dataOnly(converted), fixture.expected, fixture.name); assert.deepStrictEqual( @@ -98,7 +106,7 @@ const results = cases.map((fixture) => { }; }); const report = { - fixtureVersion: 2, + fixtureVersion: 3, mode: prepared ? "prepared" : "legacy", node: process.version, platform: `${os.platform()} ${os.arch()}`, diff --git a/packages/rescript-relay/benchmarks/results/size-before.json b/packages/rescript-relay/benchmarks/results/size-before.json new file mode 100644 index 00000000..be4c2af9 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-before.json @@ -0,0 +1,792 @@ +{ + "fixtureVersion": 1, + "esbuild": "0.25.12", + "node": "v24.16.0", + "artifactCount": 129, + "combined": { + "minified": 313772, + "gzip": 41628, + "brotli": 29248 + }, + "separate": { + "minified": 342285, + "gzip": 126052, + "brotli": 112258 + }, + "files": [ + { + "path": "__tests__/__generated__/GroupAvatar_group_graphql.bs.js", + "minified": 848, + "gzip": 498, + "brotli": 428 + }, + { + "path": "__tests__/__generated__/HasNameComponent_hasName_graphql.bs.js", + "minified": 942, + "gzip": 517, + "brotli": 448 + }, + { + "path": "__tests__/__generated__/LocalUser____relay_model_instance_graphql.bs.js", + "minified": 1196, + "gzip": 632, + "brotli": 555 + }, + { + "path": "__tests__/__generated__/LocalUser__id_graphql.bs.js", + "minified": 884, + "gzip": 512, + "brotli": 440 + }, + { + "path": "__tests__/__generated__/LocalUser_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/Query_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/RichContent_content_graphql.bs.js", + "minified": 859, + "gzip": 497, + "brotli": 427 + }, + { + "path": "__tests__/__generated__/TestAliasedFragmentsQuery_graphql.bs.js", + "minified": 3560, + "gzip": 1233, + "brotli": 1100 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.bs.js", + "minified": 869, + "gzip": 507, + "brotli": 438 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userLastName_graphql.bs.js", + "minified": 867, + "gzip": 507, + "brotli": 436 + }, + { + "path": "__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.bs.js", + "minified": 3312, + "gzip": 1284, + "brotli": 1143 + }, + { + "path": "__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.bs.js", + "minified": 3204, + "gzip": 1231, + "brotli": 1093 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.bs.js", + "minified": 4680, + "gzip": 1463, + "brotli": 1332 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropQuery_graphql.bs.js", + "minified": 3587, + "gzip": 1356, + "brotli": 1222 + }, + { + "path": "__tests__/__generated__/TestCatchMembersPropQuery_graphql.bs.js", + "minified": 4389, + "gzip": 1450, + "brotli": 1309 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMemberQuery_graphql.bs.js", + "minified": 3429, + "gzip": 1272, + "brotli": 1132 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMember_member_graphql.bs.js", + "minified": 1599, + "gzip": 718, + "brotli": 646 + }, + { + "path": "__tests__/__generated__/TestCatchUser_user_graphql.bs.js", + "minified": 984, + "gzip": 565, + "brotli": 493 + }, + { + "path": "__tests__/__generated__/TestCodesplitQuery_graphql.bs.js", + "minified": 7429, + "gzip": 1886, + "brotli": 1711 + }, + { + "path": "__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.bs.js", + "minified": 868, + "gzip": 510, + "brotli": 439 + }, + { + "path": "__tests__/__generated__/TestConnections2_user_graphql.bs.js", + "minified": 4166, + "gzip": 1362, + "brotli": 1242 + }, + { + "path": "__tests__/__generated__/TestConnections3_user_graphql.bs.js", + "minified": 2410, + "gzip": 878, + "brotli": 787 + }, + { + "path": "__tests__/__generated__/TestConnectionsQuery_graphql.bs.js", + "minified": 4527, + "gzip": 1573, + "brotli": 1409 + }, + { + "path": "__tests__/__generated__/TestConnections_AddFriendMutation_graphql.bs.js", + "minified": 2625, + "gzip": 972, + "brotli": 866 + }, + { + "path": "__tests__/__generated__/TestConnections_user_graphql.bs.js", + "minified": 3075, + "gzip": 1092, + "brotli": 983 + }, + { + "path": "__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 3189, + "gzip": 1184, + "brotli": 1060 + }, + { + "path": "__tests__/__generated__/TestCustomScalarsQuery_graphql.bs.js", + "minified": 4938, + "gzip": 1555, + "brotli": 1398 + }, + { + "path": "__tests__/__generated__/TestFragmentQuery_graphql.bs.js", + "minified": 4740, + "gzip": 1424, + "brotli": 1281 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.bs.js", + "minified": 1040, + "gzip": 588, + "brotli": 515 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredQuery_graphql.bs.js", + "minified": 3906, + "gzip": 1237, + "brotli": 1107 + }, + { + "path": "__tests__/__generated__/TestFragmentRequired_user_graphql.bs.js", + "minified": 1027, + "gzip": 577, + "brotli": 504 + }, + { + "path": "__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.bs.js", + "minified": 1062, + "gzip": 575, + "brotli": 498 + }, + { + "path": "__tests__/__generated__/TestFragment_inline_graphql.bs.js", + "minified": 831, + "gzip": 481, + "brotli": 420 + }, + { + "path": "__tests__/__generated__/TestFragment_plural_user_graphql.bs.js", + "minified": 1133, + "gzip": 581, + "brotli": 507 + }, + { + "path": "__tests__/__generated__/TestFragment_sub_user_graphql.bs.js", + "minified": 855, + "gzip": 503, + "brotli": 433 + }, + { + "path": "__tests__/__generated__/TestFragment_user_graphql.bs.js", + "minified": 1244, + "gzip": 620, + "brotli": 535 + }, + { + "path": "__tests__/__generated__/TestInputUnionQuery_graphql.bs.js", + "minified": 2536, + "gzip": 1104, + "brotli": 971 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadQuery_graphql.bs.js", + "minified": 6273, + "gzip": 1673, + "brotli": 1505 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.bs.js", + "minified": 7017, + "gzip": 1812, + "brotli": 1638 + }, + { + "path": "__tests__/__generated__/TestLocalPayload_user_graphql.bs.js", + "minified": 2623, + "gzip": 870, + "brotli": 776 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.bs.js", + "minified": 2609, + "gzip": 1067, + "brotli": 946 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.bs.js", + "minified": 3101, + "gzip": 1234, + "brotli": 1107 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.bs.js", + "minified": 2694, + "gzip": 1088, + "brotli": 966 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.bs.js", + "minified": 2686, + "gzip": 1088, + "brotli": 971 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.bs.js", + "minified": 2607, + "gzip": 1063, + "brotli": 958 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.bs.js", + "minified": 3097, + "gzip": 1232, + "brotli": 1097 + }, + { + "path": "__tests__/__generated__/TestMutationInline_user_graphql.bs.js", + "minified": 835, + "gzip": 488, + "brotli": 426 + }, + { + "path": "__tests__/__generated__/TestMutationProvidedVariable_user_graphql.bs.js", + "minified": 1035, + "gzip": 563, + "brotli": 486 + }, + { + "path": "__tests__/__generated__/TestMutationQuery_graphql.bs.js", + "minified": 3563, + "gzip": 1263, + "brotli": 1125 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.bs.js", + "minified": 2812, + "gzip": 1058, + "brotli": 967 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.bs.js", + "minified": 3688, + "gzip": 1121, + "brotli": 1011 + }, + { + "path": "__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 3623, + "gzip": 1101, + "brotli": 981 + }, + { + "path": "__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 4721, + "gzip": 1329, + "brotli": 1205 + }, + { + "path": "__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.bs.js", + "minified": 3171, + "gzip": 1023, + "brotli": 912 + }, + { + "path": "__tests__/__generated__/TestMutation_user_graphql.bs.js", + "minified": 1860, + "gzip": 753, + "brotli": 664 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.bs.js", + "minified": 3530, + "gzip": 1301, + "brotli": 1167 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceQuery_graphql.bs.js", + "minified": 4323, + "gzip": 1391, + "brotli": 1260 + }, + { + "path": "__tests__/__generated__/TestNodeInterface_user_graphql.bs.js", + "minified": 857, + "gzip": 506, + "brotli": 434 + }, + { + "path": "__tests__/__generated__/TestNonReactQuery_graphql.bs.js", + "minified": 2830, + "gzip": 1130, + "brotli": 1000 + }, + { + "path": "__tests__/__generated__/TestNonReact_user_graphql.bs.js", + "minified": 1051, + "gzip": 570, + "brotli": 494 + }, + { + "path": "__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 3248, + "gzip": 1233, + "brotli": 1107 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesMutation_graphql.bs.js", + "minified": 3119, + "gzip": 1080, + "brotli": 988 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesQuery_graphql.bs.js", + "minified": 2565, + "gzip": 1053, + "brotli": 938 + }, + { + "path": "__tests__/__generated__/TestObserverQuery_graphql.bs.js", + "minified": 2317, + "gzip": 1025, + "brotli": 907 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeQuery_graphql.bs.js", + "minified": 4725, + "gzip": 1511, + "brotli": 1361 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.bs.js", + "minified": 5376, + "gzip": 1690, + "brotli": 1522 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_query_graphql.bs.js", + "minified": 2832, + "gzip": 1072, + "brotli": 961 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_user_graphql.bs.js", + "minified": 1199, + "gzip": 596, + "brotli": 517 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionQuery_graphql.bs.js", + "minified": 5288, + "gzip": 1614, + "brotli": 1451 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.bs.js", + "minified": 6005, + "gzip": 1785, + "brotli": 1604 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_query_graphql.bs.js", + "minified": 3940, + "gzip": 1269, + "brotli": 1141 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_user_graphql.bs.js", + "minified": 1130, + "gzip": 590, + "brotli": 509 + }, + { + "path": "__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.bs.js", + "minified": 3347, + "gzip": 1181, + "brotli": 1052 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.bs.js", + "minified": 4019, + "gzip": 1348, + "brotli": 1212 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.bs.js", + "minified": 4569, + "gzip": 1494, + "brotli": 1336 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.bs.js", + "minified": 1243, + "gzip": 603, + "brotli": 536 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user_graphql.bs.js", + "minified": 2284, + "gzip": 896, + "brotli": 794 + }, + { + "path": "__tests__/__generated__/TestProvidedVariablesQuery_graphql.bs.js", + "minified": 6031, + "gzip": 1604, + "brotli": 1451 + }, + { + "path": "__tests__/__generated__/TestProvidedVariables_user_graphql.bs.js", + "minified": 1718, + "gzip": 620, + "brotli": 545 + }, + { + "path": "__tests__/__generated__/TestQueryInputObjectsQuery_graphql.bs.js", + "minified": 2457, + "gzip": 1095, + "brotli": 963 + }, + { + "path": "__tests__/__generated__/TestQuery_graphql.bs.js", + "minified": 3099, + "gzip": 1231, + "brotli": 1104 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeQuery_graphql.bs.js", + "minified": 4181, + "gzip": 1484, + "brotli": 1347 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.bs.js", + "minified": 4215, + "gzip": 1477, + "brotli": 1328 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNode_user_graphql.bs.js", + "minified": 1842, + "gzip": 820, + "brotli": 721 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.bs.js", + "minified": 2541, + "gzip": 1071, + "brotli": 954 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgs_query_graphql.bs.js", + "minified": 1125, + "gzip": 611, + "brotli": 534 + }, + { + "path": "__tests__/__generated__/TestRefetchingQuery_graphql.bs.js", + "minified": 4097, + "gzip": 1452, + "brotli": 1300 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.bs.js", + "minified": 2583, + "gzip": 1078, + "brotli": 956 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.bs.js", + "minified": 1137, + "gzip": 616, + "brotli": 537 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordQuery_graphql.bs.js", + "minified": 4139, + "gzip": 1458, + "brotli": 1304 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.bs.js", + "minified": 4924, + "gzip": 1658, + "brotli": 1506 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecord_user_graphql.bs.js", + "minified": 2242, + "gzip": 895, + "brotli": 788 + }, + { + "path": "__tests__/__generated__/TestRefetchingRefetchQuery_graphql.bs.js", + "minified": 4882, + "gzip": 1656, + "brotli": 1496 + }, + { + "path": "__tests__/__generated__/TestRefetching_user_graphql.bs.js", + "minified": 2230, + "gzip": 891, + "brotli": 784 + }, + { + "path": "__tests__/__generated__/TestRelayResolversAllQuery_graphql.bs.js", + "minified": 5785, + "gzip": 1641, + "brotli": 1487 + }, + { + "path": "__tests__/__generated__/TestRelayResolversQuery_graphql.bs.js", + "minified": 3408, + "gzip": 1236, + "brotli": 1103 + }, + { + "path": "__tests__/__generated__/TestRelayResolvers_user_graphql.bs.js", + "minified": 1437, + "gzip": 678, + "brotli": 595 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver2_graphql.bs.js", + "minified": 931, + "gzip": 513, + "brotli": 443 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver_graphql.bs.js", + "minified": 930, + "gzip": 511, + "brotli": 442 + }, + { + "path": "__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.bs.js", + "minified": 2615, + "gzip": 1072, + "brotli": 960 + }, + { + "path": "__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.bs.js", + "minified": 2204, + "gzip": 911, + "brotli": 808 + }, + { + "path": "__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.bs.js", + "minified": 2293, + "gzip": 902, + "brotli": 786 + }, + { + "path": "__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.bs.js", + "minified": 1039, + "gzip": 565, + "brotli": 485 + }, + { + "path": "__tests__/__generated__/TestSubscriptionQuery_graphql.bs.js", + "minified": 2904, + "gzip": 1128, + "brotli": 1000 + }, + { + "path": "__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.bs.js", + "minified": 2768, + "gzip": 980, + "brotli": 889 + }, + { + "path": "__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.bs.js", + "minified": 3254, + "gzip": 1099, + "brotli": 986 + }, + { + "path": "__tests__/__generated__/TestSubscription_user_graphql.bs.js", + "minified": 1198, + "gzip": 585, + "brotli": 504 + }, + { + "path": "__tests__/__generated__/TestTestingHelpersQuery_graphql.bs.js", + "minified": 4122, + "gzip": 1400, + "brotli": 1253 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_plural_user_graphql.bs.js", + "minified": 1139, + "gzip": 589, + "brotli": 514 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_sub_user_graphql.bs.js", + "minified": 861, + "gzip": 509, + "brotli": 441 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_user_graphql.bs.js", + "minified": 1256, + "gzip": 627, + "brotli": 543 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentQuery_graphql.bs.js", + "minified": 3912, + "gzip": 1318, + "brotli": 1165 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentUser_user_graphql.bs.js", + "minified": 1060, + "gzip": 573, + "brotli": 494 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_member_graphql.bs.js", + "minified": 1632, + "gzip": 716, + "brotli": 628 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_plural_member_graphql.bs.js", + "minified": 1646, + "gzip": 727, + "brotli": 643 + }, + { + "path": "__tests__/__generated__/TestUnionsQuery_graphql.bs.js", + "minified": 5767, + "gzip": 1592, + "brotli": 1443 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.bs.js", + "minified": 3164, + "gzip": 1174, + "brotli": 1065 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_query_graphql.bs.js", + "minified": 1324, + "gzip": 625, + "brotli": 536 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_updatableUser_graphql.bs.js", + "minified": 678, + "gzip": 363, + "brotli": 321 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.bs.js", + "minified": 1428, + "gzip": 658, + "brotli": 574 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_graphql.bs.js", + "minified": 3031, + "gzip": 1148, + "brotli": 1028 + }, + { + "path": "__tests__/__generated__/UserAvatar_user_graphql.bs.js", + "minified": 1186, + "gzip": 621, + "brotli": 541 + }, + { + "path": "__tests__/__generated__/UserMeta____relay_model_instance_graphql.bs.js", + "minified": 922, + "gzip": 524, + "brotli": 450 + }, + { + "path": "__tests__/__generated__/UserMeta_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/UserName_user_graphql.bs.js", + "minified": 922, + "gzip": 507, + "brotli": 437 + }, + { + "path": "__tests__/__generated__/User_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.bs.js", + "minified": 1555, + "gzip": 619, + "brotli": 541 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.bs.js", + "minified": 5480, + "gzip": 1565, + "brotli": 1404 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.bs.js", + "minified": 2369, + "gzip": 871, + "brotli": 787 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/size-current.json b/packages/rescript-relay/benchmarks/results/size-current.json new file mode 100644 index 00000000..3528dc5d --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-current.json @@ -0,0 +1,792 @@ +{ + "fixtureVersion": 1, + "esbuild": "0.25.12", + "node": "v24.16.0", + "artifactCount": 129, + "combined": { + "minified": 277982, + "gzip": 36961, + "brotli": 26651 + }, + "separate": { + "minified": 307794, + "gzip": 119154, + "brotli": 105719 + }, + "files": [ + { + "path": "__tests__/__generated__/GroupAvatar_group_graphql.bs.js", + "minified": 711, + "gzip": 447, + "brotli": 384 + }, + { + "path": "__tests__/__generated__/HasNameComponent_hasName_graphql.bs.js", + "minified": 805, + "gzip": 467, + "brotli": 400 + }, + { + "path": "__tests__/__generated__/LocalUser____relay_model_instance_graphql.bs.js", + "minified": 1059, + "gzip": 579, + "brotli": 506 + }, + { + "path": "__tests__/__generated__/LocalUser__id_graphql.bs.js", + "minified": 747, + "gzip": 462, + "brotli": 399 + }, + { + "path": "__tests__/__generated__/LocalUser_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/Query_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/RichContent_content_graphql.bs.js", + "minified": 722, + "gzip": 447, + "brotli": 380 + }, + { + "path": "__tests__/__generated__/TestAliasedFragmentsQuery_graphql.bs.js", + "minified": 3136, + "gzip": 1125, + "brotli": 1003 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.bs.js", + "minified": 732, + "gzip": 455, + "brotli": 394 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userLastName_graphql.bs.js", + "minified": 730, + "gzip": 454, + "brotli": 391 + }, + { + "path": "__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.bs.js", + "minified": 3002, + "gzip": 1221, + "brotli": 1078 + }, + { + "path": "__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.bs.js", + "minified": 2779, + "gzip": 1170, + "brotli": 1039 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.bs.js", + "minified": 4115, + "gzip": 1392, + "brotli": 1266 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropQuery_graphql.bs.js", + "minified": 3138, + "gzip": 1292, + "brotli": 1158 + }, + { + "path": "__tests__/__generated__/TestCatchMembersPropQuery_graphql.bs.js", + "minified": 3862, + "gzip": 1385, + "brotli": 1245 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMemberQuery_graphql.bs.js", + "minified": 3073, + "gzip": 1217, + "brotli": 1078 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMember_member_graphql.bs.js", + "minified": 1528, + "gzip": 696, + "brotli": 609 + }, + { + "path": "__tests__/__generated__/TestCatchUser_user_graphql.bs.js", + "minified": 913, + "gzip": 545, + "brotli": 474 + }, + { + "path": "__tests__/__generated__/TestCodesplitQuery_graphql.bs.js", + "minified": 7005, + "gzip": 1782, + "brotli": 1615 + }, + { + "path": "__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.bs.js", + "minified": 731, + "gzip": 458, + "brotli": 393 + }, + { + "path": "__tests__/__generated__/TestConnections2_user_graphql.bs.js", + "minified": 4095, + "gzip": 1347, + "brotli": 1226 + }, + { + "path": "__tests__/__generated__/TestConnections3_user_graphql.bs.js", + "minified": 2334, + "gzip": 860, + "brotli": 766 + }, + { + "path": "__tests__/__generated__/TestConnectionsQuery_graphql.bs.js", + "minified": 4221, + "gzip": 1512, + "brotli": 1350 + }, + { + "path": "__tests__/__generated__/TestConnections_AddFriendMutation_graphql.bs.js", + "minified": 2252, + "gzip": 914, + "brotli": 809 + }, + { + "path": "__tests__/__generated__/TestConnections_user_graphql.bs.js", + "minified": 2999, + "gzip": 1075, + "brotli": 966 + }, + { + "path": "__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2735, + "gzip": 1126, + "brotli": 1001 + }, + { + "path": "__tests__/__generated__/TestCustomScalarsQuery_graphql.bs.js", + "minified": 4390, + "gzip": 1486, + "brotli": 1342 + }, + { + "path": "__tests__/__generated__/TestFragmentQuery_graphql.bs.js", + "minified": 4301, + "gzip": 1367, + "brotli": 1223 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.bs.js", + "minified": 903, + "gzip": 534, + "brotli": 463 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredQuery_graphql.bs.js", + "minified": 3467, + "gzip": 1182, + "brotli": 1050 + }, + { + "path": "__tests__/__generated__/TestFragmentRequired_user_graphql.bs.js", + "minified": 890, + "gzip": 525, + "brotli": 452 + }, + { + "path": "__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.bs.js", + "minified": 925, + "gzip": 524, + "brotli": 451 + }, + { + "path": "__tests__/__generated__/TestFragment_inline_graphql.bs.js", + "minified": 694, + "gzip": 430, + "brotli": 372 + }, + { + "path": "__tests__/__generated__/TestFragment_plural_user_graphql.bs.js", + "minified": 996, + "gzip": 531, + "brotli": 458 + }, + { + "path": "__tests__/__generated__/TestFragment_sub_user_graphql.bs.js", + "minified": 718, + "gzip": 450, + "brotli": 387 + }, + { + "path": "__tests__/__generated__/TestFragment_user_graphql.bs.js", + "minified": 1168, + "gzip": 600, + "brotli": 513 + }, + { + "path": "__tests__/__generated__/TestInputUnionQuery_graphql.bs.js", + "minified": 2163, + "gzip": 1037, + "brotli": 904 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadQuery_graphql.bs.js", + "minified": 5414, + "gzip": 1571, + "brotli": 1420 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.bs.js", + "minified": 6100, + "gzip": 1702, + "brotli": 1542 + }, + { + "path": "__tests__/__generated__/TestLocalPayload_user_graphql.bs.js", + "minified": 2552, + "gzip": 853, + "brotli": 758 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.bs.js", + "minified": 2185, + "gzip": 961, + "brotli": 844 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.bs.js", + "minified": 2744, + "gzip": 1172, + "brotli": 1043 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.bs.js", + "minified": 2337, + "gzip": 1033, + "brotli": 913 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.bs.js", + "minified": 2325, + "gzip": 1033, + "brotli": 911 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.bs.js", + "minified": 2183, + "gzip": 956, + "brotli": 844 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.bs.js", + "minified": 2740, + "gzip": 1170, + "brotli": 1047 + }, + { + "path": "__tests__/__generated__/TestMutationInline_user_graphql.bs.js", + "minified": 698, + "gzip": 434, + "brotli": 376 + }, + { + "path": "__tests__/__generated__/TestMutationProvidedVariable_user_graphql.bs.js", + "minified": 898, + "gzip": 514, + "brotli": 443 + }, + { + "path": "__tests__/__generated__/TestMutationQuery_graphql.bs.js", + "minified": 3201, + "gzip": 1208, + "brotli": 1066 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.bs.js", + "minified": 2444, + "gzip": 993, + "brotli": 885 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.bs.js", + "minified": 2994, + "gzip": 1025, + "brotli": 923 + }, + { + "path": "__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 2929, + "gzip": 1004, + "brotli": 900 + }, + { + "path": "__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 4030, + "gzip": 1237, + "brotli": 1123 + }, + { + "path": "__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.bs.js", + "minified": 2788, + "gzip": 967, + "brotli": 880 + }, + { + "path": "__tests__/__generated__/TestMutation_user_graphql.bs.js", + "minified": 1789, + "gzip": 735, + "brotli": 647 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.bs.js", + "minified": 3173, + "gzip": 1240, + "brotli": 1113 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceQuery_graphql.bs.js", + "minified": 3852, + "gzip": 1327, + "brotli": 1196 + }, + { + "path": "__tests__/__generated__/TestNodeInterface_user_graphql.bs.js", + "minified": 720, + "gzip": 454, + "brotli": 387 + }, + { + "path": "__tests__/__generated__/TestNonReactQuery_graphql.bs.js", + "minified": 2468, + "gzip": 1077, + "brotli": 944 + }, + { + "path": "__tests__/__generated__/TestNonReact_user_graphql.bs.js", + "minified": 914, + "gzip": 519, + "brotli": 447 + }, + { + "path": "__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2859, + "gzip": 1175, + "brotli": 1051 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesMutation_graphql.bs.js", + "minified": 2751, + "gzip": 1018, + "brotli": 904 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesQuery_graphql.bs.js", + "minified": 2141, + "gzip": 948, + "brotli": 834 + }, + { + "path": "__tests__/__generated__/TestObserverQuery_graphql.bs.js", + "minified": 1893, + "gzip": 922, + "brotli": 813 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeQuery_graphql.bs.js", + "minified": 4371, + "gzip": 1458, + "brotli": 1305 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.bs.js", + "minified": 5073, + "gzip": 1630, + "brotli": 1473 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_query_graphql.bs.js", + "minified": 2756, + "gzip": 1055, + "brotli": 940 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_user_graphql.bs.js", + "minified": 1062, + "gzip": 549, + "brotli": 475 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionQuery_graphql.bs.js", + "minified": 4940, + "gzip": 1564, + "brotli": 1406 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.bs.js", + "minified": 5708, + "gzip": 1728, + "brotli": 1559 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_query_graphql.bs.js", + "minified": 3869, + "gzip": 1254, + "brotli": 1126 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_user_graphql.bs.js", + "minified": 993, + "gzip": 541, + "brotli": 471 + }, + { + "path": "__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.bs.js", + "minified": 2847, + "gzip": 1122, + "brotli": 989 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.bs.js", + "minified": 3657, + "gzip": 1295, + "brotli": 1149 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.bs.js", + "minified": 4215, + "gzip": 1439, + "brotli": 1293 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.bs.js", + "minified": 1106, + "gzip": 555, + "brotli": 486 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user_graphql.bs.js", + "minified": 2208, + "gzip": 879, + "brotli": 776 + }, + { + "path": "__tests__/__generated__/TestProvidedVariablesQuery_graphql.bs.js", + "minified": 5725, + "gzip": 1542, + "brotli": 1400 + }, + { + "path": "__tests__/__generated__/TestProvidedVariables_user_graphql.bs.js", + "minified": 1581, + "gzip": 572, + "brotli": 504 + }, + { + "path": "__tests__/__generated__/TestQueryInputObjectsQuery_graphql.bs.js", + "minified": 2084, + "gzip": 1030, + "brotli": 911 + }, + { + "path": "__tests__/__generated__/TestQuery_graphql.bs.js", + "minified": 2742, + "gzip": 1179, + "brotli": 1068 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeQuery_graphql.bs.js", + "minified": 3843, + "gzip": 1422, + "brotli": 1281 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.bs.js", + "minified": 3912, + "gzip": 1420, + "brotli": 1275 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNode_user_graphql.bs.js", + "minified": 1705, + "gzip": 769, + "brotli": 668 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.bs.js", + "minified": 2193, + "gzip": 1016, + "brotli": 902 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgs_query_graphql.bs.js", + "minified": 988, + "gzip": 558, + "brotli": 485 + }, + { + "path": "__tests__/__generated__/TestRefetchingQuery_graphql.bs.js", + "minified": 3791, + "gzip": 1391, + "brotli": 1245 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.bs.js", + "minified": 2235, + "gzip": 1022, + "brotli": 905 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.bs.js", + "minified": 1000, + "gzip": 561, + "brotli": 489 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordQuery_graphql.bs.js", + "minified": 3833, + "gzip": 1397, + "brotli": 1244 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.bs.js", + "minified": 4626, + "gzip": 1600, + "brotli": 1448 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecord_user_graphql.bs.js", + "minified": 2166, + "gzip": 874, + "brotli": 768 + }, + { + "path": "__tests__/__generated__/TestRefetchingRefetchQuery_graphql.bs.js", + "minified": 4584, + "gzip": 1596, + "brotli": 1446 + }, + { + "path": "__tests__/__generated__/TestRefetching_user_graphql.bs.js", + "minified": 2154, + "gzip": 870, + "brotli": 765 + }, + { + "path": "__tests__/__generated__/TestRelayResolversAllQuery_graphql.bs.js", + "minified": 5361, + "gzip": 1536, + "brotli": 1386 + }, + { + "path": "__tests__/__generated__/TestRelayResolversQuery_graphql.bs.js", + "minified": 3046, + "gzip": 1181, + "brotli": 1052 + }, + { + "path": "__tests__/__generated__/TestRelayResolvers_user_graphql.bs.js", + "minified": 1300, + "gzip": 625, + "brotli": 542 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver2_graphql.bs.js", + "minified": 794, + "gzip": 465, + "brotli": 395 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver_graphql.bs.js", + "minified": 793, + "gzip": 463, + "brotli": 395 + }, + { + "path": "__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.bs.js", + "minified": 2191, + "gzip": 967, + "brotli": 855 + }, + { + "path": "__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.bs.js", + "minified": 1836, + "gzip": 844, + "brotli": 740 + }, + { + "path": "__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.bs.js", + "minified": 1925, + "gzip": 834, + "brotli": 728 + }, + { + "path": "__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.bs.js", + "minified": 902, + "gzip": 515, + "brotli": 443 + }, + { + "path": "__tests__/__generated__/TestSubscriptionQuery_graphql.bs.js", + "minified": 2542, + "gzip": 1073, + "brotli": 942 + }, + { + "path": "__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.bs.js", + "minified": 2552, + "gzip": 952, + "brotli": 837 + }, + { + "path": "__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.bs.js", + "minified": 3038, + "gzip": 1066, + "brotli": 953 + }, + { + "path": "__tests__/__generated__/TestSubscription_user_graphql.bs.js", + "minified": 1061, + "gzip": 535, + "brotli": 455 + }, + { + "path": "__tests__/__generated__/TestTestingHelpersQuery_graphql.bs.js", + "minified": 3448, + "gzip": 1298, + "brotli": 1170 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_plural_user_graphql.bs.js", + "minified": 1002, + "gzip": 538, + "brotli": 466 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_sub_user_graphql.bs.js", + "minified": 724, + "gzip": 458, + "brotli": 390 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_user_graphql.bs.js", + "minified": 1180, + "gzip": 607, + "brotli": 521 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentQuery_graphql.bs.js", + "minified": 3556, + "gzip": 1264, + "brotli": 1124 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentUser_user_graphql.bs.js", + "minified": 923, + "gzip": 520, + "brotli": 448 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_member_graphql.bs.js", + "minified": 1561, + "gzip": 697, + "brotli": 608 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_plural_member_graphql.bs.js", + "minified": 1575, + "gzip": 709, + "brotli": 623 + }, + { + "path": "__tests__/__generated__/TestUnionsQuery_graphql.bs.js", + "minified": 5235, + "gzip": 1525, + "brotli": 1383 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.bs.js", + "minified": 2816, + "gzip": 1121, + "brotli": 997 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_query_graphql.bs.js", + "minified": 1248, + "gzip": 607, + "brotli": 517 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_updatableUser_graphql.bs.js", + "minified": 678, + "gzip": 363, + "brotli": 321 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.bs.js", + "minified": 1298, + "gzip": 610, + "brotli": 529 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_graphql.bs.js", + "minified": 2607, + "gzip": 1046, + "brotli": 936 + }, + { + "path": "__tests__/__generated__/UserAvatar_user_graphql.bs.js", + "minified": 1049, + "gzip": 572, + "brotli": 494 + }, + { + "path": "__tests__/__generated__/UserMeta____relay_model_instance_graphql.bs.js", + "minified": 785, + "gzip": 476, + "brotli": 404 + }, + { + "path": "__tests__/__generated__/UserMeta_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/UserName_user_graphql.bs.js", + "minified": 785, + "gzip": 458, + "brotli": 393 + }, + { + "path": "__tests__/__generated__/User_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.bs.js", + "minified": 1418, + "gzip": 570, + "brotli": 499 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.bs.js", + "minified": 5142, + "gzip": 1500, + "brotli": 1351 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.bs.js", + "minified": 2295, + "gzip": 849, + "brotli": 767 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/size-original.json b/packages/rescript-relay/benchmarks/results/size-original.json new file mode 100644 index 00000000..dbdcdfde --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-original.json @@ -0,0 +1,792 @@ +{ + "fixtureVersion": 1, + "esbuild": "0.25.12", + "node": "v24.16.0", + "artifactCount": 129, + "combined": { + "minified": 284957, + "gzip": 37573, + "brotli": 26976 + }, + "separate": { + "minified": 314589, + "gzip": 119093, + "brotli": 106076 + }, + "files": [ + { + "path": "__tests__/__generated__/GroupAvatar_group_graphql.bs.js", + "minified": 765, + "gzip": 464, + "brotli": 396 + }, + { + "path": "__tests__/__generated__/HasNameComponent_hasName_graphql.bs.js", + "minified": 859, + "gzip": 484, + "brotli": 418 + }, + { + "path": "__tests__/__generated__/LocalUser____relay_model_instance_graphql.bs.js", + "minified": 1113, + "gzip": 598, + "brotli": 521 + }, + { + "path": "__tests__/__generated__/LocalUser__id_graphql.bs.js", + "minified": 801, + "gzip": 480, + "brotli": 406 + }, + { + "path": "__tests__/__generated__/LocalUser_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/Query_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/RichContent_content_graphql.bs.js", + "minified": 776, + "gzip": 464, + "brotli": 396 + }, + { + "path": "__tests__/__generated__/TestAliasedFragmentsQuery_graphql.bs.js", + "minified": 3290, + "gzip": 1170, + "brotli": 1048 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.bs.js", + "minified": 786, + "gzip": 475, + "brotli": 409 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userLastName_graphql.bs.js", + "minified": 784, + "gzip": 474, + "brotli": 408 + }, + { + "path": "__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.bs.js", + "minified": 2943, + "gzip": 1200, + "brotli": 1060 + }, + { + "path": "__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.bs.js", + "minified": 2882, + "gzip": 1166, + "brotli": 1042 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.bs.js", + "minified": 4316, + "gzip": 1383, + "brotli": 1260 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropQuery_graphql.bs.js", + "minified": 3265, + "gzip": 1286, + "brotli": 1152 + }, + { + "path": "__tests__/__generated__/TestCatchMembersPropQuery_graphql.bs.js", + "minified": 3983, + "gzip": 1364, + "brotli": 1234 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMemberQuery_graphql.bs.js", + "minified": 3143, + "gzip": 1208, + "brotli": 1078 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMember_member_graphql.bs.js", + "minified": 1494, + "gzip": 677, + "brotli": 592 + }, + { + "path": "__tests__/__generated__/TestCatchUser_user_graphql.bs.js", + "minified": 894, + "gzip": 529, + "brotli": 456 + }, + { + "path": "__tests__/__generated__/TestCodesplitQuery_graphql.bs.js", + "minified": 7159, + "gzip": 1825, + "brotli": 1649 + }, + { + "path": "__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.bs.js", + "minified": 785, + "gzip": 477, + "brotli": 405 + }, + { + "path": "__tests__/__generated__/TestConnections2_user_graphql.bs.js", + "minified": 4019, + "gzip": 1315, + "brotli": 1192 + }, + { + "path": "__tests__/__generated__/TestConnections3_user_graphql.bs.js", + "minified": 2269, + "gzip": 830, + "brotli": 746 + }, + { + "path": "__tests__/__generated__/TestConnectionsQuery_graphql.bs.js", + "minified": 4236, + "gzip": 1504, + "brotli": 1353 + }, + { + "path": "__tests__/__generated__/TestConnections_AddFriendMutation_graphql.bs.js", + "minified": 2342, + "gzip": 898, + "brotli": 796 + }, + { + "path": "__tests__/__generated__/TestConnections_user_graphql.bs.js", + "minified": 2949, + "gzip": 1045, + "brotli": 953 + }, + { + "path": "__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2861, + "gzip": 1121, + "brotli": 1003 + }, + { + "path": "__tests__/__generated__/TestCustomScalarsQuery_graphql.bs.js", + "minified": 4455, + "gzip": 1475, + "brotli": 1336 + }, + { + "path": "__tests__/__generated__/TestFragmentQuery_graphql.bs.js", + "minified": 4348, + "gzip": 1341, + "brotli": 1205 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.bs.js", + "minified": 957, + "gzip": 550, + "brotli": 480 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredQuery_graphql.bs.js", + "minified": 3514, + "gzip": 1157, + "brotli": 1038 + }, + { + "path": "__tests__/__generated__/TestFragmentRequired_user_graphql.bs.js", + "minified": 944, + "gzip": 542, + "brotli": 469 + }, + { + "path": "__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.bs.js", + "minified": 979, + "gzip": 541, + "brotli": 465 + }, + { + "path": "__tests__/__generated__/TestFragment_inline_graphql.bs.js", + "minified": 748, + "gzip": 449, + "brotli": 388 + }, + { + "path": "__tests__/__generated__/TestFragment_plural_user_graphql.bs.js", + "minified": 1050, + "gzip": 548, + "brotli": 476 + }, + { + "path": "__tests__/__generated__/TestFragment_sub_user_graphql.bs.js", + "minified": 772, + "gzip": 469, + "brotli": 404 + }, + { + "path": "__tests__/__generated__/TestFragment_user_graphql.bs.js", + "minified": 1157, + "gzip": 587, + "brotli": 505 + }, + { + "path": "__tests__/__generated__/TestInputUnionQuery_graphql.bs.js", + "minified": 2224, + "gzip": 1034, + "brotli": 907 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadQuery_graphql.bs.js", + "minified": 5717, + "gzip": 1560, + "brotli": 1416 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.bs.js", + "minified": 6391, + "gzip": 1697, + "brotli": 1559 + }, + { + "path": "__tests__/__generated__/TestLocalPayload_user_graphql.bs.js", + "minified": 2499, + "gzip": 825, + "brotli": 735 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.bs.js", + "minified": 2339, + "gzip": 1005, + "brotli": 891 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.bs.js", + "minified": 2823, + "gzip": 1170, + "brotli": 1061 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.bs.js", + "minified": 2362, + "gzip": 1007, + "brotli": 900 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.bs.js", + "minified": 2346, + "gzip": 1006, + "brotli": 895 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.bs.js", + "minified": 2337, + "gzip": 1001, + "brotli": 887 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.bs.js", + "minified": 2819, + "gzip": 1170, + "brotli": 1044 + }, + { + "path": "__tests__/__generated__/TestMutationInline_user_graphql.bs.js", + "minified": 752, + "gzip": 454, + "brotli": 393 + }, + { + "path": "__tests__/__generated__/TestMutationProvidedVariable_user_graphql.bs.js", + "minified": 952, + "gzip": 530, + "brotli": 458 + }, + { + "path": "__tests__/__generated__/TestMutationQuery_graphql.bs.js", + "minified": 3277, + "gzip": 1196, + "brotli": 1066 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.bs.js", + "minified": 2488, + "gzip": 982, + "brotli": 884 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.bs.js", + "minified": 3238, + "gzip": 1032, + "brotli": 929 + }, + { + "path": "__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 3173, + "gzip": 1014, + "brotli": 912 + }, + { + "path": "__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 4241, + "gzip": 1223, + "brotli": 1110 + }, + { + "path": "__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.bs.js", + "minified": 2897, + "gzip": 959, + "brotli": 858 + }, + { + "path": "__tests__/__generated__/TestMutation_user_graphql.bs.js", + "minified": 1766, + "gzip": 708, + "brotli": 646 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.bs.js", + "minified": 3252, + "gzip": 1238, + "brotli": 1114 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceQuery_graphql.bs.js", + "minified": 3981, + "gzip": 1323, + "brotli": 1195 + }, + { + "path": "__tests__/__generated__/TestNodeInterface_user_graphql.bs.js", + "minified": 774, + "gzip": 473, + "brotli": 403 + }, + { + "path": "__tests__/__generated__/TestNonReactQuery_graphql.bs.js", + "minified": 2544, + "gzip": 1068, + "brotli": 944 + }, + { + "path": "__tests__/__generated__/TestNonReact_user_graphql.bs.js", + "minified": 968, + "gzip": 536, + "brotli": 463 + }, + { + "path": "__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2952, + "gzip": 1167, + "brotli": 1046 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesMutation_graphql.bs.js", + "minified": 2826, + "gzip": 1017, + "brotli": 921 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesQuery_graphql.bs.js", + "minified": 2295, + "gzip": 993, + "brotli": 884 + }, + { + "path": "__tests__/__generated__/TestObserverQuery_graphql.bs.js", + "minified": 2047, + "gzip": 966, + "brotli": 861 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeQuery_graphql.bs.js", + "minified": 4439, + "gzip": 1448, + "brotli": 1298 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.bs.js", + "minified": 5058, + "gzip": 1616, + "brotli": 1469 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_query_graphql.bs.js", + "minified": 2693, + "gzip": 1032, + "brotli": 922 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_user_graphql.bs.js", + "minified": 1116, + "gzip": 564, + "brotli": 486 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionQuery_graphql.bs.js", + "minified": 5010, + "gzip": 1553, + "brotli": 1395 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.bs.js", + "minified": 5695, + "gzip": 1714, + "brotli": 1548 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_query_graphql.bs.js", + "minified": 3716, + "gzip": 1206, + "brotli": 1087 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_user_graphql.bs.js", + "minified": 1047, + "gzip": 556, + "brotli": 485 + }, + { + "path": "__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.bs.js", + "minified": 2929, + "gzip": 1112, + "brotli": 1002 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.bs.js", + "minified": 3733, + "gzip": 1284, + "brotli": 1157 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.bs.js", + "minified": 4283, + "gzip": 1429, + "brotli": 1280 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.bs.js", + "minified": 1160, + "gzip": 572, + "brotli": 504 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user_graphql.bs.js", + "minified": 2184, + "gzip": 859, + "brotli": 762 + }, + { + "path": "__tests__/__generated__/TestProvidedVariablesQuery_graphql.bs.js", + "minified": 5584, + "gzip": 1523, + "brotli": 1384 + }, + { + "path": "__tests__/__generated__/TestProvidedVariables_user_graphql.bs.js", + "minified": 1635, + "gzip": 588, + "brotli": 512 + }, + { + "path": "__tests__/__generated__/TestQueryInputObjectsQuery_graphql.bs.js", + "minified": 2156, + "gzip": 1014, + "brotli": 890 + }, + { + "path": "__tests__/__generated__/TestQuery_graphql.bs.js", + "minified": 2767, + "gzip": 1149, + "brotli": 1036 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeQuery_graphql.bs.js", + "minified": 3826, + "gzip": 1405, + "brotli": 1266 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.bs.js", + "minified": 3890, + "gzip": 1401, + "brotli": 1260 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNode_user_graphql.bs.js", + "minified": 1759, + "gzip": 787, + "brotli": 682 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.bs.js", + "minified": 2263, + "gzip": 1007, + "brotli": 896 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgs_query_graphql.bs.js", + "minified": 1042, + "gzip": 573, + "brotli": 500 + }, + { + "path": "__tests__/__generated__/TestRefetchingQuery_graphql.bs.js", + "minified": 3792, + "gzip": 1385, + "brotli": 1234 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.bs.js", + "minified": 2305, + "gzip": 1013, + "brotli": 902 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.bs.js", + "minified": 1054, + "gzip": 579, + "brotli": 503 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordQuery_graphql.bs.js", + "minified": 3834, + "gzip": 1391, + "brotli": 1241 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.bs.js", + "minified": 4579, + "gzip": 1577, + "brotli": 1429 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecord_user_graphql.bs.js", + "minified": 2134, + "gzip": 846, + "brotli": 748 + }, + { + "path": "__tests__/__generated__/TestRefetchingRefetchQuery_graphql.bs.js", + "minified": 4537, + "gzip": 1572, + "brotli": 1424 + }, + { + "path": "__tests__/__generated__/TestRefetching_user_graphql.bs.js", + "minified": 2122, + "gzip": 841, + "brotli": 734 + }, + { + "path": "__tests__/__generated__/TestRelayResolversAllQuery_graphql.bs.js", + "minified": 5515, + "gzip": 1578, + "brotli": 1429 + }, + { + "path": "__tests__/__generated__/TestRelayResolversQuery_graphql.bs.js", + "minified": 3122, + "gzip": 1173, + "brotli": 1055 + }, + { + "path": "__tests__/__generated__/TestRelayResolvers_user_graphql.bs.js", + "minified": 1354, + "gzip": 643, + "brotli": 563 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver2_graphql.bs.js", + "minified": 848, + "gzip": 480, + "brotli": 412 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver_graphql.bs.js", + "minified": 847, + "gzip": 478, + "brotli": 410 + }, + { + "path": "__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.bs.js", + "minified": 2345, + "gzip": 1009, + "brotli": 924 + }, + { + "path": "__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.bs.js", + "minified": 1939, + "gzip": 845, + "brotli": 743 + }, + { + "path": "__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.bs.js", + "minified": 1997, + "gzip": 827, + "brotli": 760 + }, + { + "path": "__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.bs.js", + "minified": 956, + "gzip": 532, + "brotli": 455 + }, + { + "path": "__tests__/__generated__/TestSubscriptionQuery_graphql.bs.js", + "minified": 2618, + "gzip": 1064, + "brotli": 938 + }, + { + "path": "__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.bs.js", + "minified": 2591, + "gzip": 934, + "brotli": 836 + }, + { + "path": "__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.bs.js", + "minified": 3077, + "gzip": 1051, + "brotli": 930 + }, + { + "path": "__tests__/__generated__/TestSubscription_user_graphql.bs.js", + "minified": 1115, + "gzip": 551, + "brotli": 473 + }, + { + "path": "__tests__/__generated__/TestTestingHelpersQuery_graphql.bs.js", + "minified": 3660, + "gzip": 1309, + "brotli": 1178 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_plural_user_graphql.bs.js", + "minified": 1056, + "gzip": 556, + "brotli": 484 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_sub_user_graphql.bs.js", + "minified": 778, + "gzip": 476, + "brotli": 409 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_user_graphql.bs.js", + "minified": 1169, + "gzip": 593, + "brotli": 512 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentQuery_graphql.bs.js", + "minified": 3626, + "gzip": 1255, + "brotli": 1119 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentUser_user_graphql.bs.js", + "minified": 977, + "gzip": 539, + "brotli": 462 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_member_graphql.bs.js", + "minified": 1532, + "gzip": 675, + "brotli": 596 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_plural_member_graphql.bs.js", + "minified": 1546, + "gzip": 688, + "brotli": 604 + }, + { + "path": "__tests__/__generated__/TestUnionsQuery_graphql.bs.js", + "minified": 5357, + "gzip": 1507, + "brotli": 1371 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.bs.js", + "minified": 2886, + "gzip": 1113, + "brotli": 993 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_query_graphql.bs.js", + "minified": 1233, + "gzip": 592, + "brotli": 509 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_updatableUser_graphql.bs.js", + "minified": 678, + "gzip": 363, + "brotli": 321 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.bs.js", + "minified": 1328, + "gzip": 621, + "brotli": 542 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_graphql.bs.js", + "minified": 2761, + "gzip": 1088, + "brotli": 982 + }, + { + "path": "__tests__/__generated__/UserAvatar_user_graphql.bs.js", + "minified": 1103, + "gzip": 588, + "brotli": 509 + }, + { + "path": "__tests__/__generated__/UserMeta____relay_model_instance_graphql.bs.js", + "minified": 839, + "gzip": 491, + "brotli": 423 + }, + { + "path": "__tests__/__generated__/UserMeta_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/UserName_user_graphql.bs.js", + "minified": 839, + "gzip": 473, + "brotli": 408 + }, + { + "path": "__tests__/__generated__/User_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.bs.js", + "minified": 1472, + "gzip": 586, + "brotli": 508 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.bs.js", + "minified": 5021, + "gzip": 1469, + "brotli": 1326 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.bs.js", + "minified": 2144, + "gzip": 820, + "brotli": 731 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/size-runtime.json b/packages/rescript-relay/benchmarks/results/size-runtime.json new file mode 100644 index 00000000..46b94b7f --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-runtime.json @@ -0,0 +1,21 @@ +{ + "esbuild": "0.25.12", + "node": "v24.16.0", + "results": { + "original": { + "minified": 2916, + "gzip": 1144, + "brotli": 1010 + }, + "before": { + "minified": 5605, + "gzip": 2261, + "brotli": 2041 + }, + "current": { + "minified": 5786, + "gzip": 2330, + "brotli": 2108 + } + } +} diff --git a/packages/rescript-relay/benchmarks/size-budgets.json b/packages/rescript-relay/benchmarks/size-budgets.json new file mode 100644 index 00000000..09a95d8b --- /dev/null +++ b/packages/rescript-relay/benchmarks/size-budgets.json @@ -0,0 +1,12 @@ +{ + "combined": { + "minified": 283542, + "gzip": 37700, + "brotli": 27184 + }, + "separate": { + "minified": 313950, + "gzip": 121537, + "brotli": 107833 + } +} diff --git a/packages/rescript-relay/benchmarks/size-fixtures.json b/packages/rescript-relay/benchmarks/size-fixtures.json new file mode 100644 index 00000000..17e4b545 --- /dev/null +++ b/packages/rescript-relay/benchmarks/size-fixtures.json @@ -0,0 +1,131 @@ +[ + "__tests__/__generated__/GroupAvatar_group_graphql.bs.js", + "__tests__/__generated__/HasNameComponent_hasName_graphql.bs.js", + "__tests__/__generated__/LocalUser____relay_model_instance_graphql.bs.js", + "__tests__/__generated__/LocalUser__id_graphql.bs.js", + "__tests__/__generated__/LocalUser_relayResolvers_graphql.bs.js", + "__tests__/__generated__/Query_relayResolvers_graphql.bs.js", + "__tests__/__generated__/RichContent_content_graphql.bs.js", + "__tests__/__generated__/TestAliasedFragmentsQuery_graphql.bs.js", + "__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.bs.js", + "__tests__/__generated__/TestAliasedFragments_userLastName_graphql.bs.js", + "__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.bs.js", + "__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.bs.js", + "__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.bs.js", + "__tests__/__generated__/TestCatchMemberPropQuery_graphql.bs.js", + "__tests__/__generated__/TestCatchMembersPropQuery_graphql.bs.js", + "__tests__/__generated__/TestCatchUnionMemberQuery_graphql.bs.js", + "__tests__/__generated__/TestCatchUnionMember_member_graphql.bs.js", + "__tests__/__generated__/TestCatchUser_user_graphql.bs.js", + "__tests__/__generated__/TestCodesplitQuery_graphql.bs.js", + "__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.bs.js", + "__tests__/__generated__/TestConnections2_user_graphql.bs.js", + "__tests__/__generated__/TestConnections3_user_graphql.bs.js", + "__tests__/__generated__/TestConnectionsQuery_graphql.bs.js", + "__tests__/__generated__/TestConnections_AddFriendMutation_graphql.bs.js", + "__tests__/__generated__/TestConnections_user_graphql.bs.js", + "__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.bs.js", + "__tests__/__generated__/TestCustomScalarsQuery_graphql.bs.js", + "__tests__/__generated__/TestFragmentQuery_graphql.bs.js", + "__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.bs.js", + "__tests__/__generated__/TestFragmentRequiredQuery_graphql.bs.js", + "__tests__/__generated__/TestFragmentRequired_user_graphql.bs.js", + "__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.bs.js", + "__tests__/__generated__/TestFragment_inline_graphql.bs.js", + "__tests__/__generated__/TestFragment_plural_user_graphql.bs.js", + "__tests__/__generated__/TestFragment_sub_user_graphql.bs.js", + "__tests__/__generated__/TestFragment_user_graphql.bs.js", + "__tests__/__generated__/TestInputUnionQuery_graphql.bs.js", + "__tests__/__generated__/TestLocalPayloadQuery_graphql.bs.js", + "__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.bs.js", + "__tests__/__generated__/TestLocalPayload_user_graphql.bs.js", + "__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.bs.js", + "__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.bs.js", + "__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.bs.js", + "__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.bs.js", + "__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.bs.js", + "__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.bs.js", + "__tests__/__generated__/TestMutationInline_user_graphql.bs.js", + "__tests__/__generated__/TestMutationProvidedVariable_user_graphql.bs.js", + "__tests__/__generated__/TestMutationQuery_graphql.bs.js", + "__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.bs.js", + "__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.bs.js", + "__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.bs.js", + "__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.bs.js", + "__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.bs.js", + "__tests__/__generated__/TestMutation_user_graphql.bs.js", + "__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.bs.js", + "__tests__/__generated__/TestNodeInterfaceQuery_graphql.bs.js", + "__tests__/__generated__/TestNodeInterface_user_graphql.bs.js", + "__tests__/__generated__/TestNonReactQuery_graphql.bs.js", + "__tests__/__generated__/TestNonReact_user_graphql.bs.js", + "__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.bs.js", + "__tests__/__generated__/TestNullableVariablesMutation_graphql.bs.js", + "__tests__/__generated__/TestNullableVariablesQuery_graphql.bs.js", + "__tests__/__generated__/TestObserverQuery_graphql.bs.js", + "__tests__/__generated__/TestPaginationInNodeQuery_graphql.bs.js", + "__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.bs.js", + "__tests__/__generated__/TestPaginationInNode_query_graphql.bs.js", + "__tests__/__generated__/TestPaginationInNode_user_graphql.bs.js", + "__tests__/__generated__/TestPaginationUnionQuery_graphql.bs.js", + "__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.bs.js", + "__tests__/__generated__/TestPaginationUnion_query_graphql.bs.js", + "__tests__/__generated__/TestPaginationUnion_user_graphql.bs.js", + "__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.bs.js", + "__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.bs.js", + "__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.bs.js", + "__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.bs.js", + "__tests__/__generated__/TestPrefetchablePagination_user_graphql.bs.js", + "__tests__/__generated__/TestProvidedVariablesQuery_graphql.bs.js", + "__tests__/__generated__/TestProvidedVariables_user_graphql.bs.js", + "__tests__/__generated__/TestQueryInputObjectsQuery_graphql.bs.js", + "__tests__/__generated__/TestQuery_graphql.bs.js", + "__tests__/__generated__/TestRefetchingInNodeQuery_graphql.bs.js", + "__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.bs.js", + "__tests__/__generated__/TestRefetchingInNode_user_graphql.bs.js", + "__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.bs.js", + "__tests__/__generated__/TestRefetchingNoArgs_query_graphql.bs.js", + "__tests__/__generated__/TestRefetchingQuery_graphql.bs.js", + "__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.bs.js", + "__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.bs.js", + "__tests__/__generated__/TestRefetchingRecordQuery_graphql.bs.js", + "__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.bs.js", + "__tests__/__generated__/TestRefetchingRecord_user_graphql.bs.js", + "__tests__/__generated__/TestRefetchingRefetchQuery_graphql.bs.js", + "__tests__/__generated__/TestRefetching_user_graphql.bs.js", + "__tests__/__generated__/TestRelayResolversAllQuery_graphql.bs.js", + "__tests__/__generated__/TestRelayResolversQuery_graphql.bs.js", + "__tests__/__generated__/TestRelayResolvers_user_graphql.bs.js", + "__tests__/__generated__/TestRelayUserResolver2_graphql.bs.js", + "__tests__/__generated__/TestRelayUserResolver_graphql.bs.js", + "__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.bs.js", + "__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.bs.js", + "__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.bs.js", + "__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.bs.js", + "__tests__/__generated__/TestSubscriptionQuery_graphql.bs.js", + "__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.bs.js", + "__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.bs.js", + "__tests__/__generated__/TestSubscription_user_graphql.bs.js", + "__tests__/__generated__/TestTestingHelpersQuery_graphql.bs.js", + "__tests__/__generated__/TestTestingHelpers_plural_user_graphql.bs.js", + "__tests__/__generated__/TestTestingHelpers_sub_user_graphql.bs.js", + "__tests__/__generated__/TestTestingHelpers_user_graphql.bs.js", + "__tests__/__generated__/TestUnionFragmentQuery_graphql.bs.js", + "__tests__/__generated__/TestUnionFragmentUser_user_graphql.bs.js", + "__tests__/__generated__/TestUnionFragment_member_graphql.bs.js", + "__tests__/__generated__/TestUnionFragment_plural_member_graphql.bs.js", + "__tests__/__generated__/TestUnionsQuery_graphql.bs.js", + "__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.bs.js", + "__tests__/__generated__/TestUpdatableFragments_query_graphql.bs.js", + "__tests__/__generated__/TestUpdatableFragments_updatableUser_graphql.bs.js", + "__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.bs.js", + "__tests__/__generated__/TestUpdatableQuery_graphql.bs.js", + "__tests__/__generated__/UserAvatar_user_graphql.bs.js", + "__tests__/__generated__/UserMeta____relay_model_instance_graphql.bs.js", + "__tests__/__generated__/UserMeta_relayResolvers_graphql.bs.js", + "__tests__/__generated__/UserName_user_graphql.bs.js", + "__tests__/__generated__/User_relayResolvers_graphql.bs.js", + "__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.bs.js", + "__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.bs.js", + "__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.bs.js" +] diff --git a/packages/rescript-relay/package.json b/packages/rescript-relay/package.json index 7d848c01..2427cb26 100644 --- a/packages/rescript-relay/package.json +++ b/packages/rescript-relay/package.json @@ -41,34 +41,36 @@ "test:all": "yarn build && yarn test:ci && ENABLE_PERSISTING=true yarn test:ci && yarn test:conversion", "bench:conversion": "node benchmarks/conversion.js", "test:conversion:mutations": "node scripts/test-conversion-mutations.js", - "bench:conversion:prepared": "node benchmarks/conversion.js --prepared" + "bench:conversion:prepared": "node benchmarks/conversion.js --prepared", + "size:conversion": "node scripts/measure-conversion-size.js" }, "devDependencies": { + "@babel/core": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/preset-env": "^7.24.0", "@glennsl/rescript-fetch": "^0.2.0", "@rescript/react": "0.14.0", "@testing-library/jest-dom": "^5.16.3", "@testing-library/react": "^13.0.0-alpha.6", - "graphql-query-test-mock": "^0.12.1", - "jest": "^27.2.4", - "@babel/core": "^7.24.0", - "@babel/preset-env": "^7.24.0", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", "babel-jest": "^27.2.4", "babel-plugin-dynamic-import-node": "^2.3.3", + "esbuild": "0.25.12", + "graphql-query-test-mock": "^0.12.1", + "jest": "^27.2.4", "nock": "^11.7.0", "node-fetch": "^2.6.0", "react": "18.2.0", "react-dom": "18.2.0", "react-relay": "20.1.1", - "relay-test-utils": "20.1.1", "relay-runtime": "20.1.1", + "relay-test-utils": "20.1.1", "rescript": "12.3.0" }, "peerDependencies": { "@rescript/react": ">=0.13.0", "react-relay": "20.1.1", - "relay-test-utils": "20.1.1", "relay-runtime": "20.1.1", + "relay-test-utils": "20.1.1", "rescript": "^12.0.0-0" }, "peerDependenciesMeta": { diff --git a/packages/rescript-relay/scripts/build-conversion-modules.js b/packages/rescript-relay/scripts/build-conversion-modules.js index dcaf5217..8bbe02ba 100644 --- a/packages/rescript-relay/scripts/build-conversion-modules.js +++ b/packages/rescript-relay/scripts/build-conversion-modules.js @@ -16,12 +16,12 @@ function buildConversionModules(destination) { source = source.replace(exports, "export {$1};\n"); if (name === "utils") { const dependency = - 'const { prepareConversion } = require("./prepareConversion");'; - if (!source.includes(dependency)) + /const\s*\{\s*prepareConversion,\s*convertWithoutPlan,?\s*\}\s*=\s*require\("\.\/prepareConversion"\);/; + if (!dependency.test(source)) throw new Error("Missing prepared-converter import"); source = source.replace( dependency, - 'import { prepareConversion } from "./prepareConversion.mjs";', + 'import { prepareConversion, convertWithoutPlan } from "./prepareConversion.mjs";', ); } fs.writeFileSync(path.join(destination, name + ".mjs"), source); diff --git a/packages/rescript-relay/scripts/measure-conversion-size.js b/packages/rescript-relay/scripts/measure-conversion-size.js new file mode 100644 index 00000000..86d95f5d --- /dev/null +++ b/packages/rescript-relay/scripts/measure-conversion-size.js @@ -0,0 +1,133 @@ +#!/usr/bin/env node +// Measure complete compiled artifacts, not just instruction literals. Dependencies +// are external so application/runtime size is not mistaken for generated-code size. +const fs = require("fs"); +const path = require("path"); +const zlib = require("zlib"); +const esbuild = require("esbuild"); +const args = process.argv.slice(2); +const option = (name) => { + const index = args.indexOf(name); + return index < 0 ? undefined : args[index + 1]; +}; +const root = path.resolve(option("--root") || path.join(__dirname, "..")); +const manifest = JSON.parse( + fs.readFileSync( + path.join(__dirname, "../benchmarks/size-fixtures.json"), + "utf8", + ), +); +function size(bytes) { + return { + minified: bytes.length, + gzip: zlib.gzipSync(bytes, { level: 9 }).length, + brotli: zlib.brotliCompressSync(bytes, { + params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 11 }, + }).length, + }; +} +async function measure() { + const common = { + bundle: true, + minify: true, + format: "esm", + platform: "browser", + write: false, + logLevel: "silent", + plugins: [ + { + name: "external-dependencies", + setup(build) { + build.onResolve({ filter: /.*/ }, (args) => { + if (args.kind === "entry-point") return; + return { path: args.path, external: true }; + }); + }, + }, + ], + }; + const files = []; + for (const relative of manifest) { + const result = await esbuild.build({ + ...common, + entryPoints: [path.join(root, relative)], + }); + files.push({ path: relative, ...size(result.outputFiles[0].contents) }); + } + // A genuine combined bundle of all fixture modules, with dependencies external. + const combined = await esbuild.build({ + ...common, + stdin: { + contents: manifest + .map( + (p, i) => + `export * as artifact${i} from ${JSON.stringify(path.join(root, p))};`, + ) + .join("\n"), + resolveDir: root, + }, + plugins: [ + { + name: "external-dependencies", + setup(build) { + build.onResolve({ filter: /.*/ }, (args) => { + if (args.importer === "") return { path: args.path }; + return { path: args.path, external: true }; + }); + }, + }, + ], + }); + const separate = files.reduce( + (sum, file) => + Object.fromEntries( + Object.keys(sum).map((key) => [key, sum[key] + file[key]]), + ), + { minified: 0, gzip: 0, brotli: 0 }, + ); + const report = { + fixtureVersion: 1, + esbuild: esbuild.version, + node: process.version, + artifactCount: files.length, + combined: size(combined.outputFiles[0].contents), + separate, + files, + }; + console.log( + JSON.stringify( + { + artifactCount: report.artifactCount, + combined: report.combined, + separate, + }, + null, + 2, + ), + ); + if (option("--output")) + fs.writeFileSync( + option("--output"), + JSON.stringify(report, null, 2) + "\n", + ); + if (args.includes("--check")) { + // Intentional headroom. Changing the fixture manifest or minifier requires + // reviewing these budgets; these do not claim to bound an application's size. + const budgets = JSON.parse( + fs.readFileSync( + path.join(__dirname, "../benchmarks/size-budgets.json"), + "utf8", + ), + ); + for (const mode of ["combined", "separate"]) + for (const key of ["minified", "gzip", "brotli"]) + if (report[mode][key] > budgets[mode][key]) + throw new Error( + `${mode} ${key}: ${report[mode][key]} exceeds ${budgets[mode][key]}`, + ); + } +} +measure().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/packages/rescript-relay/src/RescriptRelay.res b/packages/rescript-relay/src/RescriptRelay.res index 28d58862..c19fbd0c 100644 --- a/packages/rescript-relay/src/RescriptRelay.res +++ b/packages/rescript-relay/src/RescriptRelay.res @@ -113,6 +113,9 @@ external relayFeatureFlags: featureFlags = "RelayFeatureFlags" external convertObj: ('a, dict>>, 'b, 'c) => 'd = "traverser" /**Internal: prepare the compiler's versioned conversion plan once.*/ +@module("./utils") +external convertWithoutPlan: ('input, 'nullable) => 'output = "convertWithoutPlan" + type preparedConversion @module("./utils") diff --git a/packages/rescript-relay/src/RescriptRelay.resi b/packages/rescript-relay/src/RescriptRelay.resi index 101231b7..bb71e316 100644 --- a/packages/rescript-relay/src/RescriptRelay.resi +++ b/packages/rescript-relay/src/RescriptRelay.resi @@ -211,6 +211,9 @@ external storeRootType: string = "ROOT_TYPE" external convertObj: ('a, dict>>, 'b, 'c) => 'd = "traverser" /**Internal: prepare the compiler's versioned conversion plan once.*/ +@module("./utils") +external convertWithoutPlan: ('input, 'nullable) => 'output = "convertWithoutPlan" + type preparedConversion @module("./utils") diff --git a/packages/rescript-relay/src/prepareConversion.js b/packages/rescript-relay/src/prepareConversion.js index fb92a177..a32035ca 100644 --- a/packages/rescript-relay/src/prepareConversion.js +++ b/packages/rescript-relay/src/prepareConversion.js @@ -206,4 +206,12 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { Array.isArray(value) && allowPlural ? plural(value) : convert(value); } -module.exports = { prepareConversion }; +// Shared converters contain no application callbacks or response cache. +const emptyPlan = { version: 2, roots: { __root: [] } }; +const readWithoutPlan = prepareConversion(emptyPlan, undefined, undefined); +const writeWithoutPlan = prepareConversion(emptyPlan, undefined, null); +function convertWithoutPlan(value, nullable) { + return nullable === null ? writeWithoutPlan(value) : readWithoutPlan(value); +} + +module.exports = { prepareConversion, convertWithoutPlan }; diff --git a/packages/rescript-relay/src/utils.js b/packages/rescript-relay/src/utils.js index 72f80dbc..065dd1e0 100644 --- a/packages/rescript-relay/src/utils.js +++ b/packages/rescript-relay/src/utils.js @@ -1,4 +1,7 @@ -const { prepareConversion } = require("./prepareConversion"); +const { + prepareConversion, + convertWithoutPlan, +} = require("./prepareConversion"); // Shared read-only fallback: avoid allocating an empty map for every field. var empty = Object.freeze({}); @@ -266,4 +269,9 @@ function runConversion(convert, value) { return convert(value); } -module.exports = { traverser, prepareConversion, runConversion }; +module.exports = { + traverser, + prepareConversion, + runConversion, + convertWithoutPlan, +}; diff --git a/packages/rescript-relay/yarn.lock b/packages/rescript-relay/yarn.lock index 714c2186..b3c8fa05 100644 --- a/packages/rescript-relay/yarn.lock +++ b/packages/rescript-relay/yarn.lock @@ -1181,6 +1181,136 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@esbuild/aix-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz#80fcbe36130e58b7670511e888b8e88a259ed76c" + integrity sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA== + +"@esbuild/android-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz#8aa4965f8d0a7982dc21734bf6601323a66da752" + integrity sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg== + +"@esbuild/android-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz#300712101f7f50f1d2627a162e6e09b109b6767a" + integrity sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg== + +"@esbuild/android-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz#87dfb27161202bdc958ef48bb61b09c758faee16" + integrity sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg== + +"@esbuild/darwin-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz#79197898ec1ff745d21c071e1c7cc3c802f0c1fd" + integrity sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg== + +"@esbuild/darwin-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz#146400a8562133f45c4d2eadcf37ddd09718079e" + integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA== + +"@esbuild/freebsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz#1c5f9ba7206e158fd2b24c59fa2d2c8bb47ca0fe" + integrity sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg== + +"@esbuild/freebsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz#ea631f4a36beaac4b9279fa0fcc6ca29eaeeb2b3" + integrity sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ== + +"@esbuild/linux-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz#e1066bce58394f1b1141deec8557a5f0a22f5977" + integrity sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ== + +"@esbuild/linux-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz#452cd66b20932d08bdc53a8b61c0e30baf4348b9" + integrity sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw== + +"@esbuild/linux-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz#b24f8acc45bcf54192c7f2f3be1b53e6551eafe0" + integrity sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA== + +"@esbuild/linux-loong64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz#f9cfffa7fc8322571fbc4c8b3268caf15bd81ad0" + integrity sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng== + +"@esbuild/linux-mips64el@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz#575a14bd74644ffab891adc7d7e60d275296f2cd" + integrity sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw== + +"@esbuild/linux-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz#75b99c70a95fbd5f7739d7692befe60601591869" + integrity sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA== + +"@esbuild/linux-riscv64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz#2e3259440321a44e79ddf7535c325057da875cd6" + integrity sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w== + +"@esbuild/linux-s390x@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz#17676cabbfe5928da5b2a0d6df5d58cd08db2663" + integrity sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg== + +"@esbuild/linux-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz#0583775685ca82066d04c3507f09524d3cd7a306" + integrity sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw== + +"@esbuild/netbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz#f04c4049cb2e252fe96b16fed90f70746b13f4a4" + integrity sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg== + +"@esbuild/netbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz#77da0d0a0d826d7c921eea3d40292548b258a076" + integrity sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ== + +"@esbuild/openbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz#6296f5867aedef28a81b22ab2009c786a952dccd" + integrity sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A== + +"@esbuild/openbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz#f8d23303360e27b16cf065b23bbff43c14142679" + integrity sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw== + +"@esbuild/openharmony-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz#49e0b768744a3924be0d7fd97dd6ce9b2923d88d" + integrity sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg== + +"@esbuild/sunos-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz#a6ed7d6778d67e528c81fb165b23f4911b9b13d6" + integrity sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w== + +"@esbuild/win32-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz#9ac14c378e1b653af17d08e7d3ce34caef587323" + integrity sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg== + +"@esbuild/win32-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz#918942dcbbb35cc14fca39afb91b5e6a3d127267" + integrity sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ== + +"@esbuild/win32-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5" + integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA== + "@glennsl/rescript-fetch@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@glennsl/rescript-fetch/-/rescript-fetch-0.2.0.tgz#b72085d8bb19d8b9266aaf18d59c440ddceaf8dd" @@ -2342,6 +2472,38 @@ es-set-tostringtag@^2.1.0: has-tostringtag "^1.0.2" hasown "^2.0.2" +esbuild@0.25.12: + version "0.25.12" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.12.tgz#97a1d041f4ab00c2fce2f838d2b9969a2d2a97a5" + integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.12" + "@esbuild/android-arm" "0.25.12" + "@esbuild/android-arm64" "0.25.12" + "@esbuild/android-x64" "0.25.12" + "@esbuild/darwin-arm64" "0.25.12" + "@esbuild/darwin-x64" "0.25.12" + "@esbuild/freebsd-arm64" "0.25.12" + "@esbuild/freebsd-x64" "0.25.12" + "@esbuild/linux-arm" "0.25.12" + "@esbuild/linux-arm64" "0.25.12" + "@esbuild/linux-ia32" "0.25.12" + "@esbuild/linux-loong64" "0.25.12" + "@esbuild/linux-mips64el" "0.25.12" + "@esbuild/linux-ppc64" "0.25.12" + "@esbuild/linux-riscv64" "0.25.12" + "@esbuild/linux-s390x" "0.25.12" + "@esbuild/linux-x64" "0.25.12" + "@esbuild/netbsd-arm64" "0.25.12" + "@esbuild/netbsd-x64" "0.25.12" + "@esbuild/openbsd-arm64" "0.25.12" + "@esbuild/openbsd-x64" "0.25.12" + "@esbuild/openharmony-arm64" "0.25.12" + "@esbuild/sunos-x64" "0.25.12" + "@esbuild/win32-arm64" "0.25.12" + "@esbuild/win32-ia32" "0.25.12" + "@esbuild/win32-x64" "0.25.12" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" From f366d16eb2d7025eff0f0faaf430c3b78d567b0c Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 09:11:29 +0200 Subject: [PATCH 07/23] Document complete bundle measurements and performance recheck --- packages/rescript-relay/benchmarks/RESULTS.md | 2 +- packages/rescript-relay/benchmarks/SIZE.md | 15 +++ .../results/size-perf-forward-before.json | 102 ++++++++++++++++++ .../results/size-perf-forward-current.json | 102 ++++++++++++++++++ .../results/size-perf-reverse-before.json | 102 ++++++++++++++++++ .../results/size-perf-reverse-current.json | 102 ++++++++++++++++++ .../docs/conversion-contract.md | 9 ++ 7 files changed, 433 insertions(+), 1 deletion(-) create mode 100644 packages/rescript-relay/benchmarks/results/size-perf-forward-before.json create mode 100644 packages/rescript-relay/benchmarks/results/size-perf-forward-current.json create mode 100644 packages/rescript-relay/benchmarks/results/size-perf-reverse-before.json create mode 100644 packages/rescript-relay/benchmarks/results/size-perf-reverse-current.json diff --git a/packages/rescript-relay/benchmarks/RESULTS.md b/packages/rescript-relay/benchmarks/RESULTS.md index 6b040faa..eb7000db 100644 --- a/packages/rescript-relay/benchmarks/RESULTS.md +++ b/packages/rescript-relay/benchmarks/RESULTS.md @@ -23,6 +23,6 @@ Sources: - `master`: `520cac4933c118a85cf0dffcd1a19a5dba34ad4f`, extracted `src/utils.js`. - `pr-673`: `c451c1afb3193550586f80b36b46b84c8965d355`, extracted `src/utils.js`. - `first-pass`: `3770abc`, extracted `src/utils.js`. -- `legacy` / `prepared`: the runtime checked in alongside these reports. +- `legacy` / `prepared`: the prepared runtime at `e856b90`, before the later bundle-size optimization. Use the current fixture-version 2 reports named `forward-*.json` and `reverse-*.json` for comparisons. Earlier `baseline.json`, `optimized.json`, and `pr-673.json` are historical fixture-version 1 measurements and must not be mixed with them. See [the benchmark guide](README.md) for commands. diff --git a/packages/rescript-relay/benchmarks/SIZE.md b/packages/rescript-relay/benchmarks/SIZE.md index 7736246f..e50b673c 100644 --- a/packages/rescript-relay/benchmarks/SIZE.md +++ b/packages/rescript-relay/benchmarks/SIZE.md @@ -81,3 +81,18 @@ prepared runtime is extracted from `e856b90`. The runtime remains larger than the original because it supports both protocols. Shared nullable converters add a small fixed cost while removing per-artifact initialization code. There is no measured full-app bundle result yet. + +## Performance recheck + +`size-perf-{forward,reverse}-{before,current}.json` records the post-change +performance check against `e856b90`, using the same version 3 harness for both. +Version 3 models the compiler's shared empty-plan calls as well as prepared plans; +it reports zero per-artifact preparation time when the shared converter is used. +Do not compare these reports to older fixture-version 2 reports with `--compare`. + +This run was noisy (host load averaged about 32 runnable tasks); several apparent +speedups reversed when the run order reversed. It does **not** establish an +additional speedup or a reliable regression estimate. Nonempty plans use unchanged +response traversal code; empty plans reuse that same generic nullable traversal +through a shared entry point. Unit, independent-model, mounted, and mutation tests +pass. A quieter application benchmark is still needed for precise timing deltas. diff --git a/packages/rescript-relay/benchmarks/results/size-perf-forward-before.json b/packages/rescript-relay/benchmarks/results/size-perf-forward-before.json new file mode 100644 index 00000000..519fab7b --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-perf-forward-before.json @@ -0,0 +1,102 @@ +{ + "fixtureVersion": 3, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "/tmp/relay-conversion-audit/size/prior-runtime/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "preparationNs": 9776.902999999998, + "medianNs": 203.18765624999986, + "p10Ns": 193.04925292968733, + "p90Ns": 286.70808593749985, + "opsPerSecond": 4921558.81147431 + }, + { + "name": "unchanged object", + "iterations": 409600, + "newOutputObjects": 0, + "preparationNs": 4128.35199999995, + "medianNs": 110.96232910156269, + "p10Ns": 93.99455078125007, + "p90Ns": 140.87839111328105, + "opsPerSecond": 9012067.50161769 + }, + { + "name": "nullable query", + "iterations": 204800, + "newOutputObjects": 3, + "preparationNs": 1431.5590000001066, + "medianNs": 202.2801611328129, + "p10Ns": 148.0475488281252, + "p90Ns": 311.5227929687492, + "opsPerSecond": 4943638.537757645 + }, + { + "name": "connection / 100 rows", + "iterations": 3200, + "newOutputObjects": 403, + "preparationNs": 4543.11000000007, + "medianNs": 42138.94937500001, + "p10Ns": 27849.995000000123, + "p90Ns": 53245.995000000046, + "opsPerSecond": 23731.0140578226 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 3200, + "newOutputObjects": 301, + "preparationNs": 1755.2140000007057, + "medianNs": 32837.35593750009, + "p10Ns": 15530.37281249999, + "p90Ns": 38517.774375000045, + "opsPerSecond": 30453.121801381247 + }, + { + "name": "union list / 100 rows", + "iterations": 1600, + "newOutputObjects": 302, + "preparationNs": 2868.4990000001567, + "medianNs": 37804.71250000005, + "p10Ns": 33257.77625, + "p90Ns": 45178.288749999636, + "opsPerSecond": 26451.728736199188 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "preparationNs": 3524.945999999545, + "medianNs": 20678.589375000058, + "p10Ns": 13515.776874999972, + "p90Ns": 41989.59562499965, + "opsPerSecond": 48359.198099314126 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 0, + "preparationNs": 4554.2310000000725, + "medianNs": 666.3554199218602, + "p10Ns": 481.41083984376104, + "p90Ns": 966.0760937499902, + "opsPerSecond": 1500700.6322800894 + }, + { + "name": "recursive inputs", + "iterations": 1600, + "newOutputObjects": 103, + "preparationNs": 8457.033999999112, + "medianNs": 31526.472499999727, + "p10Ns": 20369.229374999806, + "p90Ns": 48759.51250000071, + "opsPerSecond": 31719.37488407587 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/size-perf-forward-current.json b/packages/rescript-relay/benchmarks/results/size-perf-forward-current.json new file mode 100644 index 00000000..3ecff8a8 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-perf-forward-current.json @@ -0,0 +1,102 @@ +{ + "fixtureVersion": 3, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "preparationNs": 17575.714999999997, + "medianNs": 115.46565917968765, + "p10Ns": 109.94398925781246, + "p90Ns": 217.77763671875007, + "opsPerSecond": 8660583.649756853 + }, + { + "name": "unchanged object", + "iterations": 409600, + "newOutputObjects": 0, + "preparationNs": 0, + "medianNs": 66.43720947265619, + "p10Ns": 57.158791503906244, + "p90Ns": 186.7120776367187, + "opsPerSecond": 15051806.17815644 + }, + { + "name": "nullable query", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 0, + "medianNs": 167.93248046874984, + "p10Ns": 150.55474609374951, + "p90Ns": 261.51394775390634, + "opsPerSecond": 5954774.187868247 + }, + { + "name": "connection / 100 rows", + "iterations": 3200, + "newOutputObjects": 403, + "preparationNs": 3672.4960000001374, + "medianNs": 26391.065625000036, + "p10Ns": 23787.179374999996, + "p90Ns": 45069.14625000008, + "opsPerSecond": 37891.61128274822 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 1600, + "newOutputObjects": 301, + "preparationNs": 2230.7369999998627, + "medianNs": 19132.703125000036, + "p10Ns": 16630.06875000008, + "p90Ns": 33063.09437500033, + "opsPerSecond": 52266.52990257999 + }, + { + "name": "union list / 100 rows", + "iterations": 3200, + "newOutputObjects": 302, + "preparationNs": 3426.3180000007196, + "medianNs": 24334.706250000127, + "p10Ns": 16858.60843750021, + "p90Ns": 37503.3775, + "opsPerSecond": 41093.57186097099 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "preparationNs": 2098.8369999995484, + "medianNs": 12521.882031250016, + "p10Ns": 11703.86609375001, + "p90Ns": 17578.603593750016, + "opsPerSecond": 79860.19972911161 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 0, + "preparationNs": 1653.4209999999803, + "medianNs": 470.69791992187857, + "p10Ns": 430.332587890625, + "p90Ns": 794.3403710937513, + "opsPerSecond": 2124504.82076906 + }, + { + "name": "recursive inputs", + "iterations": 3200, + "newOutputObjects": 103, + "preparationNs": 4278.997999999774, + "medianNs": 23955.590625000124, + "p10Ns": 17811.185625000122, + "p90Ns": 29746.338749999948, + "opsPerSecond": 41743.909204910065 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/size-perf-reverse-before.json b/packages/rescript-relay/benchmarks/results/size-perf-reverse-before.json new file mode 100644 index 00000000..d8a1ad77 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-perf-reverse-before.json @@ -0,0 +1,102 @@ +{ + "fixtureVersion": 3, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "/tmp/relay-conversion-audit/size/prior-runtime/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 4196.099, + "medianNs": 117.18968017578123, + "p10Ns": 115.08749267578125, + "p90Ns": 160.97857666015625, + "opsPerSecond": 8533174.58073124 + }, + { + "name": "unchanged object", + "iterations": 819200, + "newOutputObjects": 0, + "preparationNs": 1343.170999999984, + "medianNs": 59.47453613281251, + "p10Ns": 56.43236938476542, + "p90Ns": 67.88435668945326, + "opsPerSecond": 16813918.443464633 + }, + { + "name": "nullable query", + "iterations": 204800, + "newOutputObjects": 3, + "preparationNs": 940.7770000000255, + "medianNs": 156.74259765624976, + "p10Ns": 147.97614257812563, + "p90Ns": 210.13202636718688, + "opsPerSecond": 6379886.609976234 + }, + { + "name": "connection / 100 rows", + "iterations": 3200, + "newOutputObjects": 403, + "preparationNs": 10279.673000000003, + "medianNs": 19944.135625000003, + "p10Ns": 19355.123437500053, + "p90Ns": 24975.94500000005, + "opsPerSecond": 50140.05213374595 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 3200, + "newOutputObjects": 301, + "preparationNs": 1270.542999999634, + "medianNs": 14908.731875, + "p10Ns": 13966.044999999951, + "p90Ns": 19967.02875000011, + "opsPerSecond": 67074.78599684723 + }, + { + "name": "union list / 100 rows", + "iterations": 3200, + "newOutputObjects": 302, + "preparationNs": 8542.061999999532, + "medianNs": 18627.90093749993, + "p10Ns": 17898.641562499906, + "p90Ns": 24174.324687500073, + "opsPerSecond": 53682.91378374761 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "preparationNs": 1914.6059999993668, + "medianNs": 11811.361718749966, + "p10Ns": 11393.46203125001, + "p90Ns": 15107.100468750046, + "opsPerSecond": 84664.24310861196 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 0, + "preparationNs": 1720.7579999994778, + "medianNs": 470.8270312500052, + "p10Ns": 441.6747070312521, + "p90Ns": 764.5654296875026, + "opsPerSecond": 2123922.233914833 + }, + { + "name": "recursive inputs", + "iterations": 3200, + "newOutputObjects": 103, + "preparationNs": 3102.8529999994134, + "medianNs": 16371.944062499893, + "p10Ns": 15326.054687499776, + "p90Ns": 21332.098124999848, + "opsPerSecond": 61080.101189113535 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/size-perf-reverse-current.json b/packages/rescript-relay/benchmarks/results/size-perf-reverse-current.json new file mode 100644 index 00000000..9aeac462 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-perf-reverse-current.json @@ -0,0 +1,102 @@ +{ + "fixtureVersion": 3, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "implementation": "src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 9097.019, + "medianNs": 119.27940429687479, + "p10Ns": 106.52258300781232, + "p90Ns": 216.27204589843768, + "opsPerSecond": 8383677.013603268 + }, + { + "name": "unchanged object", + "iterations": 819200, + "newOutputObjects": 0, + "preparationNs": 0, + "medianNs": 59.3171533203124, + "p10Ns": 54.28314086914049, + "p90Ns": 80.1415173339845, + "opsPerSecond": 16858529.852233533 + }, + { + "name": "nullable query", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 0, + "medianNs": 214.0196875, + "p10Ns": 153.00184326171862, + "p90Ns": 292.52293945312476, + "opsPerSecond": 4672467.340183365 + }, + { + "name": "connection / 100 rows", + "iterations": 1600, + "newOutputObjects": 403, + "preparationNs": 3614.755000000059, + "medianNs": 25448.43312499978, + "p10Ns": 24583.15812500018, + "p90Ns": 30770.828750000306, + "opsPerSecond": 39295.1501213499 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 400, + "newOutputObjects": 301, + "preparationNs": 1732.0100000006278, + "medianNs": 25535.37249999863, + "p10Ns": 15496.4300000006, + "p90Ns": 26433.52749999849, + "opsPerSecond": 39161.36332062724 + }, + { + "name": "union list / 100 rows", + "iterations": 1600, + "newOutputObjects": 302, + "preparationNs": 6779.786000000058, + "medianNs": 19382.96874999992, + "p10Ns": 18112.0924999999, + "p90Ns": 21482.186874999912, + "opsPerSecond": 51591.68406542492 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "preparationNs": 1833.1520000001547, + "medianNs": 11957.052812500136, + "p10Ns": 11725.159062499984, + "p90Ns": 13631.066250000005, + "opsPerSecond": 83632.64892119406 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 0, + "preparationNs": 1684.4590000000608, + "medianNs": 437.20769531250704, + "p10Ns": 425.51439453125005, + "p90Ns": 469.33061523437124, + "opsPerSecond": 2287242.4495758717 + }, + { + "name": "recursive inputs", + "iterations": 3200, + "newOutputObjects": 103, + "preparationNs": 3244.8920000006183, + "medianNs": 17352.02968750002, + "p10Ns": 16154.881249999846, + "p90Ns": 21942.977187499935, + "opsPerSecond": 57630.14575294184 + } + ] +} diff --git a/packages/rescript-relay/docs/conversion-contract.md b/packages/rescript-relay/docs/conversion-contract.md index 2693751b..0746e62e 100644 --- a/packages/rescript-relay/docs/conversion-contract.md +++ b/packages/rescript-relay/docs/conversion-contract.md @@ -111,3 +111,12 @@ The runtime is tested through both CommonJS and native ESM release modules. Run `yarn test:all` and `yarn test:conversion:mutations` from the package. The mutation check runs isolated copies and requires behavioral test failures for 13 deliberately introduced faults; it does not claim a comprehensive mutation score. + +## Generated size and sharing + +Generated helper metadata and handles are private to each artifact. Equal plans +can be shared between directions, but callback maps and prepared handles remain +separate. Empty plans reuse the runtime's callback-free nullable converter, which +retains neither inputs nor application callbacks. The named version 2 plan format +and response semantics are unchanged. See [size measurements](../benchmarks/SIZE.md) +for complete generated-artifact bundles, separate gzip/Brotli totals, and CI budgets. From 3a55220c267d410fa3ecc7120a32e18c1bf06167 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 09:26:46 +0200 Subject: [PATCH 08/23] Shrink generated conversion instructions with local callback IDs --- packages/relay | 2 +- ...ayUnderlyingScalarSiblingQuery_graphql.res | 18 +- ...TestCatchLoggedInUserPropQuery_graphql.res | 14 +- ...TestCatchMemberPropNestedQuery_graphql.res | 22 +- .../TestCatchMemberPropQuery_graphql.res | 18 +- .../TestCatchMembersPropQuery_graphql.res | 18 +- .../TestCatchUnionMemberQuery_graphql.res | 8 +- .../TestCatchUnionMember_member_graphql.res | 10 +- .../TestCatchUser_user_graphql.res | 8 +- .../TestConnections2_user_graphql.res | 8 +- .../TestConnections3_user_graphql.res | 4 +- .../TestConnectionsQuery_graphql.res | 16 +- ...tConnections_AddFriendMutation_graphql.res | 4 +- .../TestConnections_user_graphql.res | 4 +- .../TestConversionPlanQuery_graphql.res | 26 +- ...larAfterCustomScalarArrayQuery_graphql.res | 18 +- .../TestCustomScalarsQuery_graphql.res | 28 +- .../TestFragmentQuery_graphql.res | 8 +- .../TestFragmentRequiredQuery_graphql.res | 8 +- .../TestFragment_user_graphql.res | 4 +- .../TestInputUnionQuery_graphql.res | 4 +- .../TestLocalPayloadQuery_graphql.res | 30 +- ...alPayloadViaNodeInterfaceQuery_graphql.res | 40 +- .../TestLocalPayload_user_graphql.res | 12 +- ...issingFieldHandlersLinkedQuery_graphql.res | 14 +- ...ieldHandlersPluralBestiesQuery_graphql.res | 8 +- ...issingFieldHandlersPluralQuery_graphql.res | 8 +- ...issingFieldHandlersScalarQuery_graphql.res | 14 +- .../TestMutationQuery_graphql.res | 8 +- ...SetOnlineStatusComplexMutation_graphql.res | 8 +- ...utationSetOnlineStatusMutation_graphql.res | 8 +- ...ragmentSetOnlineStatusMutation_graphql.res | 8 +- ...ragmentSetOnlineStatusMutation_graphql.res | 22 +- ...ovidedVariableFragmentMutation_graphql.res | 8 +- .../TestMutation_user_graphql.res | 8 +- ...deInterfaceOnAbstractTypeQuery_graphql.res | 14 +- .../TestNodeInterfaceQuery_graphql.res | 18 +- .../TestNonReactQuery_graphql.res | 8 +- ...arsAfterCustomScalarArrayQuery_graphql.res | 14 +- .../TestNullableVariablesMutation_graphql.res | 8 +- .../TestPaginationInNodeQuery_graphql.res | 8 +- ...stPaginationInNodeRefetchQuery_graphql.res | 12 +- .../TestPaginationInNode_query_graphql.res | 4 +- .../TestPaginationUnionQuery_graphql.res | 8 +- ...estPaginationUnionRefetchQuery_graphql.res | 12 +- .../TestPaginationUnion_query_graphql.res | 8 +- ...estParseCustomScalarArrayQuery_graphql.res | 14 +- ...estPrefetchablePaginationQuery_graphql.res | 8 +- ...etchablePaginationRefetchQuery_graphql.res | 8 +- ...estPrefetchablePagination_user_graphql.res | 4 +- .../TestProvidedVariablesQuery_graphql.res | 16 +- .../TestQueryInputObjectsQuery_graphql.res | 4 +- .../__generated__/TestQuery_graphql.res | 8 +- .../TestRefetchingInNodeQuery_graphql.res | 18 +- ...stRefetchingInNodeRefetchQuery_graphql.res | 12 +- ...stRefetchingNoArgsRefetchQuery_graphql.res | 8 +- .../TestRefetchingQuery_graphql.res | 18 +- ...tchingRecordNoArgsRefetchQuery_graphql.res | 8 +- .../TestRefetchingRecordQuery_graphql.res | 18 +- ...stRefetchingRecordRefetchQuery_graphql.res | 18 +- .../TestRefetchingRecord_user_graphql.res | 4 +- .../TestRefetchingRefetchQuery_graphql.res | 18 +- .../TestRefetching_user_graphql.res | 4 +- .../TestRelayResolversQuery_graphql.res | 8 +- ...alizeCustomScalarArrayMutation_graphql.res | 8 +- ...eMultipleCustomScalarsMutation_graphql.res | 10 +- .../TestSubscriptionQuery_graphql.res | 8 +- ...riptionUserUpdatedSubscription_graphql.res | 4 +- ...edVariableFragmentSubscription_graphql.res | 4 +- .../TestTestingHelpersQuery_graphql.res | 8 +- .../TestTestingHelpers_user_graphql.res | 4 +- .../TestUnionFragmentQuery_graphql.res | 8 +- .../TestUnionFragment_member_graphql.res | 8 +- ...estUnionFragment_plural_member_graphql.res | 8 +- .../__generated__/TestUnionsQuery_graphql.res | 18 +- .../TestUpdatableFragmentsQuery_graphql.res | 8 +- .../TestUpdatableFragments_query_graphql.res | 4 +- .../__tests__/utils-prepared-tests.js | 25 + .../TestPreloadedQuery_graphql.res | 16 +- ...TestPreloadedQuery_preloadable_graphql.res | 8 +- packages/rescript-relay/benchmarks/SIZE.md | 37 +- .../results/size-callback-slots.json | 792 ++++++++++++++++++ .../benchmarks/size-budgets.json | 12 +- .../docs/conversion-contract.md | 6 + 84 files changed, 1304 insertions(+), 448 deletions(-) create mode 100644 packages/rescript-relay/benchmarks/results/size-callback-slots.json diff --git a/packages/relay b/packages/relay index 8abad4d1..6cb6cee5 160000 --- a/packages/relay +++ b/packages/relay @@ -1 +1 @@ -Subproject commit 8abad4d19429615a7d1bfd819c4c14e64fe55862 +Subproject commit 6cb6cee5a4d0ff0e9d2d0aad37214e46cce19209 diff --git a/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res index 43dfce82..b53670cb 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res @@ -41,16 +41,16 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["aaNumber"],"scalar":"TestsUtils.Number"},{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["aaNumber"],"scalar":"1"},{"path":["beforeDate"],"scalar":"0"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.Number": TestsUtils.Number.serialize, - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, + let variablesCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": TestsUtils.Number.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -62,11 +62,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friends"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -78,11 +78,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res index a1359455..24ffdd29 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.res @@ -31,15 +31,15 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"path":["loggedInUser","createdAt","value"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"path":["loggedInUser","createdAt","value"],"scalar":"0"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, + let wrapResponseCallbacks = { + "0": TestsUtils.Datetime.serialize, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -51,13 +51,13 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.parse, + let responseCallbacks = { + "0": TestsUtils.Datetime.parse, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res index f774d78b..69e503f6 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.res @@ -52,17 +52,17 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member"],"union":"response_member"},{"path":["member","User","memberOfSingular","value"],"union":"response_member_User_memberOfSingular_value"},{"path":["member","User","memberOfSingular","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member"],"union":"1"},{"path":["member","User","memberOfSingular","value"],"union":"2"},{"path":["member","User","memberOfSingular","value","User","createdAt"],"scalar":"0"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "response_member_User_memberOfSingular_value": wrap_response_member_User_memberOfSingular_value, - "response_member": wrap_response_member, + let wrapResponseCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": wrap_response_member, + "2": wrap_response_member_User_memberOfSingular_value, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -74,15 +74,15 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.parse, - "response_member_User_memberOfSingular_value": unwrap_response_member_User_memberOfSingular_value, - "response_member": unwrap_response_member, + let responseCallbacks = { + "0": TestsUtils.Datetime.parse, + "1": unwrap_response_member, + "2": unwrap_response_member_User_memberOfSingular_value, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res index 3f082f78..fe93f9c8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchMemberPropQuery_graphql.res @@ -39,16 +39,16 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member","value"],"union":"response_member_value"},{"path":["member","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member","value"],"union":"1"},{"path":["member","value","User","createdAt"],"scalar":"0"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "response_member_value": wrap_response_member_value, + let wrapResponseCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": wrap_response_member_value, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -60,14 +60,14 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.parse, - "response_member_value": unwrap_response_member_value, + let responseCallbacks = { + "0": TestsUtils.Datetime.parse, + "1": unwrap_response_member_value, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res index 9ef52d6b..4722ea86 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchMembersPropQuery_graphql.res @@ -45,16 +45,16 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node","value"],"union":"response_members_edges_node_value"},{"path":["members","edges","node","value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node","value"],"union":"1"},{"path":["members","edges","node","value","User","createdAt"],"scalar":"0"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "response_members_edges_node_value": wrap_response_members_edges_node_value, + let wrapResponseCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": wrap_response_members_edges_node_value, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -66,14 +66,14 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.parse, - "response_members_edges_node_value": unwrap_response_members_edges_node_value, + let responseCallbacks = { + "0": TestsUtils.Datetime.parse, + "1": unwrap_response_members_edges_node_value, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res index ea89086a..f2318937 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMemberQuery_graphql.res @@ -32,11 +32,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -48,11 +48,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res index b0b56d04..9ca244b7 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchUnionMember_member_graphql.res @@ -31,16 +31,16 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value"],"union":"fragment_t"},{"path":["value","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value"],"union":"1"},{"path":["value","User","createdAt"],"scalar":"0"}]},"version":2}`) @live - let fragmentConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.parse, - "fragment_t": unwrap_fragment_t, + let fragmentCallbacks = { + "0": TestsUtils.Datetime.parse, + "1": unwrap_fragment_t, } @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res index 7c470874..7fe06912 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCatchUser_user_graphql.res @@ -15,15 +15,15 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value","createdAt"],"scalar":"0"}]},"version":2}`) @live - let fragmentConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.parse, + let fragmentCallbacks = { + "0": TestsUtils.Datetime.parse, } @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res index c8bc6cc3..5d68ec80 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res @@ -35,15 +35,15 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member"],"union":"fragment_member"},{"list":1,"path":["member","User","friendsConnection","edges"]}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member"],"union":"0"},{"list":1,"path":["member","User","friendsConnection","edges"]}]},"version":2}`) @live - let fragmentConverterMap = { - "fragment_member": unwrap_fragment_member, + let fragmentCallbacks = { + "0": unwrap_fragment_member, } @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res index ead10032..8dc4016d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res @@ -28,11 +28,11 @@ module Internal = { @live let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friendsConnection","edges"]}]},"version":2}`) @live - let fragmentConverterMap = () + let fragmentCallbacks = () @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res index 52e27f6c..a4bdbddb 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnectionsQuery_graphql.res @@ -34,15 +34,15 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, + let variablesCallbacks = { + "0": TestsUtils.Datetime.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -54,11 +54,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -70,11 +70,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res index 77729902..e61bfb83 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res @@ -30,11 +30,11 @@ module Internal = { @live let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["connections"]}]},"version":2}`) @live - let variablesConverterMap = () + let variablesCallbacks = () @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res index e10b6bfe..73a1701e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res @@ -26,11 +26,11 @@ module Internal = { @live let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsConnection","edges"]}]},"version":2}`) @live - let fragmentConverterMap = () + let fragmentCallbacks = () @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res index 6628828e..1eabf136 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPlanQuery_graphql.res @@ -42,15 +42,15 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"conversionContractInput"}],"conversionContractInput":[{"list":1,"path":["children"],"reference":"conversionContractInput"},{"list":2,"path":["grid"],"scalar":"TestsUtils.ConversionNumber"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"conversionContractInput"}],"conversionContractInput":[{"list":1,"path":["children"],"reference":"conversionContractInput"},{"list":2,"path":["grid"],"scalar":"0"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.ConversionNumber": TestsUtils.ConversionNumber.serialize, + let variablesCallbacks = { + "0": TestsUtils.ConversionNumber.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -60,16 +60,16 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["conversionContract","a","b"],"scalar":"TestsUtils.Datetime"},{"path":["conversionContract","a_b"],"scalar":"TestsUtils.ConversionNumber"},{"list":1,"path":["conversionContract","dates"],"scalar":"TestsUtils.Datetime"},{"list":2,"path":["conversionContract","grid"],"scalar":"TestsUtils.ConversionNumber"},{"list":2,"opaque":true,"path":["conversionContract","raw"]}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["conversionContract","a","b"],"scalar":"1"},{"path":["conversionContract","a_b"],"scalar":"0"},{"list":1,"path":["conversionContract","dates"],"scalar":"1"},{"list":2,"path":["conversionContract","grid"],"scalar":"0"},{"list":2,"opaque":true,"path":["conversionContract","raw"]}]},"version":2}`) @live - let wrapResponseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "TestsUtils.ConversionNumber": TestsUtils.ConversionNumber.serialize, + let wrapResponseCallbacks = { + "0": TestsUtils.ConversionNumber.serialize, + "1": TestsUtils.Datetime.serialize, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -81,14 +81,14 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.parse, - "TestsUtils.ConversionNumber": TestsUtils.ConversionNumber.parse, + let responseCallbacks = { + "0": TestsUtils.ConversionNumber.parse, + "1": TestsUtils.Datetime.parse, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res index fc227326..5b5f885d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.res @@ -30,16 +30,16 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"0"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"1"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "TestsUtils.IntString": TestsUtils.IntString.serialize, + let wrapResponseCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": TestsUtils.IntString.serialize, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -51,14 +51,14 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.parse, - "TestsUtils.IntString": TestsUtils.IntString.parse, + let responseCallbacks = { + "0": TestsUtils.Datetime.parse, + "1": TestsUtils.IntString.parse, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res index 8ca73558..2152794b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestCustomScalarsQuery_graphql.res @@ -55,16 +55,16 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"},{"path":["number"],"scalar":"1"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "TestsUtils.Number": TestsUtils.Number.serialize, + let variablesCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": TestsUtils.Number.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -74,16 +74,16 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["loggedInUser","friends"]},{"path":["loggedInUser","friends","createdAt"],"scalar":"TestsUtils.Datetime"},{"path":["member"],"union":"response_member"},{"path":["member","User","createdAt"],"scalar":"TestsUtils.Datetime"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","createdAt"],"scalar":"0"},{"list":1,"path":["loggedInUser","friends"]},{"path":["loggedInUser","friends","createdAt"],"scalar":"0"},{"path":["member"],"union":"1"},{"path":["member","User","createdAt"],"scalar":"0"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "response_member": wrap_response_member, + let wrapResponseCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": wrap_response_member, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -95,14 +95,14 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.parse, - "response_member": unwrap_response_member, + let responseCallbacks = { + "0": TestsUtils.Datetime.parse, + "1": unwrap_response_member, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res index 63fa8d47..b537547f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentQuery_graphql.res @@ -43,11 +43,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -59,11 +59,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res index 28839394..27737ddc 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragmentRequiredQuery_graphql.res @@ -42,11 +42,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -58,11 +58,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res index e975fdf5..a150a804 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestFragment_user_graphql.res @@ -19,11 +19,11 @@ module Internal = { @live let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live - let fragmentConverterMap = () + let fragmentCallbacks = () @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res index b8b12e8e..2dead8a0 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestInputUnionQuery_graphql.res @@ -36,11 +36,11 @@ module Internal = { @live let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["location"],"reference":"location"}],"byAddress":[],"byLoc":[],"location":[{"path":["byAddress"],"reference":"byAddress"},{"path":["byLoc"],"reference":"byLoc"}]},"version":2}`) @live - let variablesConverterMap = () + let variablesCallbacks = () @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res index 3d0a0270..a8e639f8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadQuery_graphql.res @@ -100,11 +100,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -116,11 +116,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) @@ -130,17 +130,17 @@ module Internal = { type wrapRawResponseRaw %%private( @live - let wrapRawResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","memberOf"],"union":"rawResponse_loggedInUser_memberOf"},{"path":["loggedInUser","memberOf","Group","topMember"],"union":"rawResponse_loggedInUser_memberOf_Group_topMember"},{"path":["loggedInUser","memberOfSingular"],"union":"rawResponse_loggedInUser_memberOfSingular"}]},"version":2}`) + let wrapRawResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","memberOf"],"union":"0"},{"path":["loggedInUser","memberOf","Group","topMember"],"union":"2"},{"path":["loggedInUser","memberOfSingular"],"union":"1"}]},"version":2}`) @live - let wrapRawResponseConverterMap = { - "rawResponse_loggedInUser_memberOf_Group_topMember": wrap_rawResponse_loggedInUser_memberOf_Group_topMember, - "rawResponse_loggedInUser_memberOf": wrap_rawResponse_loggedInUser_memberOf, - "rawResponse_loggedInUser_memberOfSingular": wrap_rawResponse_loggedInUser_memberOfSingular, + let wrapRawResponseCallbacks = { + "0": wrap_rawResponse_loggedInUser_memberOf, + "1": wrap_rawResponse_loggedInUser_memberOfSingular, + "2": wrap_rawResponse_loggedInUser_memberOf_Group_topMember, } @live let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( wrapRawResponseConverter, - wrapRawResponseConverterMap, + wrapRawResponseCallbacks, null ) ) @@ -152,15 +152,15 @@ module Internal = { @live let rawResponseConverter = wrapRawResponseConverter @live - let rawResponseConverterMap = { - "rawResponse_loggedInUser_memberOf_Group_topMember": unwrap_rawResponse_loggedInUser_memberOf_Group_topMember, - "rawResponse_loggedInUser_memberOf": unwrap_rawResponse_loggedInUser_memberOf, - "rawResponse_loggedInUser_memberOfSingular": unwrap_rawResponse_loggedInUser_memberOfSingular, + let rawResponseCallbacks = { + "0": unwrap_rawResponse_loggedInUser_memberOf, + "1": unwrap_rawResponse_loggedInUser_memberOfSingular, + "2": unwrap_rawResponse_loggedInUser_memberOf_Group_topMember, } @live let preparedRawResponseConverter = RescriptRelay.prepareConversion( rawResponseConverter, - rawResponseConverterMap, + rawResponseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res index 31714d80..0db7b9cd 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.res @@ -123,15 +123,15 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"0"},{"fragments":true,"path":["node","User"]}]},"version":2}`) @live - let wrapResponseConverterMap = { - "response_node": wrap_response_node, + let wrapResponseCallbacks = { + "0": wrap_response_node, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -143,13 +143,13 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "response_node": unwrap_response_node, + let responseCallbacks = { + "0": unwrap_response_node, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) @@ -159,18 +159,18 @@ module Internal = { type wrapRawResponseRaw %%private( @live - let wrapRawResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"rawResponse_node"},{"list":1,"path":["node","User","memberOf"],"union":"rawResponse_node_User_memberOf"},{"path":["node","User","memberOf","Group","topMember"],"union":"rawResponse_node_User_memberOf_Group_topMember"},{"path":["node","User","memberOfSingular"],"union":"rawResponse_node_User_memberOfSingular"}]},"version":2}`) + let wrapRawResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"0"},{"list":1,"path":["node","User","memberOf"],"union":"1"},{"path":["node","User","memberOf","Group","topMember"],"union":"3"},{"path":["node","User","memberOfSingular"],"union":"2"}]},"version":2}`) @live - let wrapRawResponseConverterMap = { - "rawResponse_node_User_memberOf_Group_topMember": wrap_rawResponse_node_User_memberOf_Group_topMember, - "rawResponse_node_User_memberOf": wrap_rawResponse_node_User_memberOf, - "rawResponse_node_User_memberOfSingular": wrap_rawResponse_node_User_memberOfSingular, - "rawResponse_node": wrap_rawResponse_node, + let wrapRawResponseCallbacks = { + "0": wrap_rawResponse_node, + "1": wrap_rawResponse_node_User_memberOf, + "2": wrap_rawResponse_node_User_memberOfSingular, + "3": wrap_rawResponse_node_User_memberOf_Group_topMember, } @live let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( wrapRawResponseConverter, - wrapRawResponseConverterMap, + wrapRawResponseCallbacks, null ) ) @@ -182,16 +182,16 @@ module Internal = { @live let rawResponseConverter = wrapRawResponseConverter @live - let rawResponseConverterMap = { - "rawResponse_node_User_memberOf_Group_topMember": unwrap_rawResponse_node_User_memberOf_Group_topMember, - "rawResponse_node_User_memberOf": unwrap_rawResponse_node_User_memberOf, - "rawResponse_node_User_memberOfSingular": unwrap_rawResponse_node_User_memberOfSingular, - "rawResponse_node": unwrap_rawResponse_node, + let rawResponseCallbacks = { + "0": unwrap_rawResponse_node, + "1": unwrap_rawResponse_node_User_memberOf, + "2": unwrap_rawResponse_node_User_memberOfSingular, + "3": unwrap_rawResponse_node_User_memberOf_Group_topMember, } @live let preparedRawResponseConverter = RescriptRelay.prepareConversion( rawResponseConverter, - rawResponseConverterMap, + rawResponseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res index 04aa4c3c..2a7a64b5 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestLocalPayload_user_graphql.res @@ -65,17 +65,17 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"fragment_memberOf"},{"path":["memberOf","Group","topMember"],"union":"fragment_memberOf_Group_topMember"},{"path":["memberOfSingular"],"union":"fragment_memberOfSingular"}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"0"},{"path":["memberOf","Group","topMember"],"union":"2"},{"path":["memberOfSingular"],"union":"1"}]},"version":2}`) @live - let fragmentConverterMap = { - "fragment_memberOf_Group_topMember": unwrap_fragment_memberOf_Group_topMember, - "fragment_memberOf": unwrap_fragment_memberOf, - "fragment_memberOfSingular": unwrap_fragment_memberOfSingular, + let fragmentCallbacks = { + "0": unwrap_fragment_memberOf, + "1": unwrap_fragment_memberOfSingular, + "2": unwrap_fragment_memberOf_Group_topMember, } @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res index 167c81ae..c5bf5b76 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.res @@ -38,15 +38,15 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"0"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "response_node": wrap_response_node, + let wrapResponseCallbacks = { + "0": wrap_response_node, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -58,13 +58,13 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "response_node": unwrap_response_node, + let responseCallbacks = { + "0": unwrap_response_node, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res index a9237efa..9520cd48 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res @@ -31,11 +31,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["onlineBesties"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -47,11 +47,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res index 8cf169e7..c1ba5ec2 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res @@ -31,11 +31,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["topOnlineUserList"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -47,11 +47,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res index 84e3752c..aedf4f5d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.res @@ -38,15 +38,15 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"0"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "response_node": wrap_response_node, + let wrapResponseCallbacks = { + "0": wrap_response_node, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -58,13 +58,13 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "response_node": unwrap_response_node, + let responseCallbacks = { + "0": unwrap_response_node, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res index e93faae8..da2bd916 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationQuery_graphql.res @@ -31,11 +31,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -47,11 +47,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res index fd3b176f..7c38ed04 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.res @@ -30,15 +30,15 @@ module Types = { module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"setOnlineStatusInput"}],"recursiveSetOnlineStatusInput":[{"path":["setOnlineStatus"],"reference":"setOnlineStatusInput"},{"path":["someValue"],"scalar":"TestsUtils.IntString"}],"setOnlineStatusInput":[{"path":["recursed"],"reference":"recursiveSetOnlineStatusInput"},{"opaque":true,"path":["someJsonValue"]}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"setOnlineStatusInput"}],"recursiveSetOnlineStatusInput":[{"path":["setOnlineStatus"],"reference":"setOnlineStatusInput"},{"path":["someValue"],"scalar":"0"}],"setOnlineStatusInput":[{"path":["recursed"],"reference":"recursiveSetOnlineStatusInput"},{"opaque":true,"path":["someJsonValue"]}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.IntString": TestsUtils.IntString.serialize, + let variablesCallbacks = { + "0": TestsUtils.IntString.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res index b895427e..eadf26e5 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.res @@ -49,11 +49,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -65,11 +65,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res index c9438302..19df643f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.res @@ -46,11 +46,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -62,11 +62,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res index 13f609ac..475fa9ce 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.res @@ -68,11 +68,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["setOnlineStatus","user"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -84,11 +84,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) @@ -98,15 +98,15 @@ module Internal = { type wrapRawResponseRaw %%private( @live - let wrapRawResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["setOnlineStatus","user","memberOf"],"union":"rawResponse_setOnlineStatus_user_memberOf"}]},"version":2}`) + let wrapRawResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["setOnlineStatus","user","memberOf"],"union":"0"}]},"version":2}`) @live - let wrapRawResponseConverterMap = { - "rawResponse_setOnlineStatus_user_memberOf": wrap_rawResponse_setOnlineStatus_user_memberOf, + let wrapRawResponseCallbacks = { + "0": wrap_rawResponse_setOnlineStatus_user_memberOf, } @live let preparedWrapRawResponseConverter = RescriptRelay.prepareConversion( wrapRawResponseConverter, - wrapRawResponseConverterMap, + wrapRawResponseCallbacks, null ) ) @@ -118,13 +118,13 @@ module Internal = { @live let rawResponseConverter = wrapRawResponseConverter @live - let rawResponseConverterMap = { - "rawResponse_setOnlineStatus_user_memberOf": unwrap_rawResponse_setOnlineStatus_user_memberOf, + let rawResponseCallbacks = { + "0": unwrap_rawResponse_setOnlineStatus_user_memberOf, } @live let preparedRawResponseConverter = RescriptRelay.prepareConversion( rawResponseConverter, - rawResponseConverterMap, + rawResponseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res index 0958ef3e..732590e4 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.res @@ -31,11 +31,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["updateUserAvatar","user"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -47,11 +47,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res index 9de582bd..f45fe136 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMutation_user_graphql.res @@ -35,15 +35,15 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"fragment_memberOf"}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["memberOf"],"union":"0"}]},"version":2}`) @live - let fragmentConverterMap = { - "fragment_memberOf": unwrap_fragment_memberOf, + let fragmentCallbacks = { + "0": unwrap_fragment_memberOf, } @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res index 321b1205..b9f3070d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.res @@ -43,15 +43,15 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"0"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "response_node": wrap_response_node, + let wrapResponseCallbacks = { + "0": wrap_response_node, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -63,13 +63,13 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "response_node": unwrap_response_node, + let responseCallbacks = { + "0": unwrap_response_node, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res index 7e6321e6..ff70d555 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNodeInterfaceQuery_graphql.res @@ -55,16 +55,16 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["_testExhaustiveInterface"],"union":"response__testExhaustiveInterface"},{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["_testExhaustiveInterface"],"union":"0"},{"path":["node"],"union":"1"},{"fragments":true,"path":["node","User"]}]},"version":2}`) @live - let wrapResponseConverterMap = { - "response__testExhaustiveInterface": wrap_response__testExhaustiveInterface, - "response_node": wrap_response_node, + let wrapResponseCallbacks = { + "0": wrap_response__testExhaustiveInterface, + "1": wrap_response_node, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -76,14 +76,14 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "response__testExhaustiveInterface": unwrap_response__testExhaustiveInterface, - "response_node": unwrap_response_node, + let responseCallbacks = { + "0": unwrap_response__testExhaustiveInterface, + "1": unwrap_response_node, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res index 4cb0026c..aa574124 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNonReactQuery_graphql.res @@ -32,11 +32,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -48,11 +48,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res index af7078aa..eaff0a20 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.res @@ -34,15 +34,15 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","intStrings"],"scalar":"0"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "TestsUtils.IntString": TestsUtils.IntString.serialize, + let wrapResponseCallbacks = { + "0": TestsUtils.IntString.serialize, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -54,13 +54,13 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "TestsUtils.IntString": TestsUtils.IntString.parse, + let responseCallbacks = { + "0": TestsUtils.IntString.parse, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res index 9da3b644..398519a3 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestNullableVariablesMutation_graphql.res @@ -30,15 +30,15 @@ module Types = { module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["someInput"],"reference":"someInput"}],"someInput":[{"path":["datetime"],"scalar":"TestsUtils.Datetime"},{"path":["recursive"],"reference":"someInput"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["someInput"],"reference":"someInput"}],"someInput":[{"path":["datetime"],"scalar":"0"},{"path":["recursive"],"reference":"someInput"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, + let variablesCallbacks = { + "0": TestsUtils.Datetime.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, null ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res index bd0cdba9..187aa528 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeQuery_graphql.res @@ -42,11 +42,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -58,11 +58,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res index 0b3f5a9b..b383411d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res @@ -51,11 +51,11 @@ module Internal = { @live let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}`) @live - let variablesConverterMap = () + let variablesCallbacks = () @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -67,11 +67,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -83,11 +83,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res index 8c504bd9..3b4b019f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNode_query_graphql.res @@ -27,11 +27,11 @@ module Internal = { @live let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsConnection","edges"]},{"fragments":true,"path":["friendsConnection","edges","node"]}]},"version":2}`) @live - let fragmentConverterMap = () + let fragmentCallbacks = () @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res index 51850cc2..20069298 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionQuery_graphql.res @@ -37,11 +37,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -53,11 +53,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res index bcbb6737..4799c026 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res @@ -46,11 +46,11 @@ module Internal = { @live let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}`) @live - let variablesConverterMap = () + let variablesCallbacks = () @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -62,11 +62,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -78,11 +78,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res index 6fc54819..42448a74 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res @@ -50,15 +50,15 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"fragment_members_edges_node"},{"list":1,"path":["members","edges","node","Group","adminsConnection","edges"]},{"fragments":true,"path":["members","edges","node","User"]}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"0"},{"list":1,"path":["members","edges","node","Group","adminsConnection","edges"]},{"fragments":true,"path":["members","edges","node","User"]}]},"version":2}`) @live - let fragmentConverterMap = { - "fragment_members_edges_node": unwrap_fragment_members_edges_node, + let fragmentCallbacks = { + "0": unwrap_fragment_members_edges_node, } @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res index ecde0227..5dea813a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res @@ -32,15 +32,15 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","intString"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["loggedInUser","justStrings"]}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","intString"],"scalar":"0"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"0"},{"list":1,"path":["loggedInUser","justStrings"]}]},"version":2}`) @live - let wrapResponseConverterMap = { - "TestsUtils.IntString": TestsUtils.IntString.serialize, + let wrapResponseCallbacks = { + "0": TestsUtils.IntString.serialize, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -52,13 +52,13 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "TestsUtils.IntString": TestsUtils.IntString.parse, + let responseCallbacks = { + "0": TestsUtils.IntString.parse, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res index f4ae7328..19e0b42e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.res @@ -31,11 +31,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -47,11 +47,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res index 242da595..76689d24 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.res @@ -51,11 +51,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -67,11 +67,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res index 71d9527d..8856681d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPrefetchablePagination_user_graphql.res @@ -28,11 +28,11 @@ module Internal = { @live let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"list":1,"path":["friendsConnection","edges"]}]},"version":2}`) @live - let fragmentConverterMap = () + let fragmentCallbacks = () @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res index 7911f12c..e2cba6d2 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestProvidedVariablesQuery_graphql.res @@ -26,15 +26,15 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesIntStrArr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"0"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesIntStrArr"],"scalar":"0"}],"inputC":[{"path":["intStr"],"scalar":"0"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.IntString": TestsUtils.IntString.serialize, + let variablesCallbacks = { + "0": TestsUtils.IntString.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -46,11 +46,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -62,11 +62,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res index f371554a..db17e25a 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res @@ -34,11 +34,11 @@ module Internal = { @live let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"searchInput"}],"searchInput":[{"list":1,"path":["names"]}]},"version":2}`) @live - let variablesConverterMap = () + let variablesCallbacks = () @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res index 9d8559f2..a55ac2ce 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res @@ -48,11 +48,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["users","edges"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -64,11 +64,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res index b281ee61..d01e9202 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res @@ -49,11 +49,11 @@ module Internal = { @live let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}`) @live - let variablesConverterMap = () + let variablesCallbacks = () @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -63,15 +63,15 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"response_node"},{"fragments":true,"path":["node","User"]}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["node"],"union":"0"},{"fragments":true,"path":["node","User"]}]},"version":2}`) @live - let wrapResponseConverterMap = { - "response_node": wrap_response_node, + let wrapResponseCallbacks = { + "0": wrap_response_node, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -83,13 +83,13 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "response_node": unwrap_response_node, + let responseCallbacks = { + "0": unwrap_response_node, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res index b3ccde93..8eaf5d2e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res @@ -47,11 +47,11 @@ module Internal = { @live let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}`) @live - let variablesConverterMap = () + let variablesCallbacks = () @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -63,11 +63,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -79,11 +79,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res index 78d59f6a..68013b4c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.res @@ -29,11 +29,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -45,11 +45,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res index cbcadd05..1408dd19 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingQuery_graphql.res @@ -42,16 +42,16 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"},{"path":["number"],"scalar":"1"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "TestsUtils.Number": TestsUtils.Number.serialize, + let variablesCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": TestsUtils.Number.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -63,11 +63,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -79,11 +79,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res index 573944f1..c3b67e42 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.res @@ -29,11 +29,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -45,11 +45,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res index d01428dd..9f67dc0e 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordQuery_graphql.res @@ -42,16 +42,16 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"},{"path":["number"],"scalar":"1"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "TestsUtils.Number": TestsUtils.Number.serialize, + let variablesCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": TestsUtils.Number.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -63,11 +63,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -79,11 +79,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res index aaa853b0..a4eb8ac8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res @@ -53,16 +53,16 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"1"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "TestsUtils.Number": TestsUtils.Number.serialize, + let variablesCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": TestsUtils.Number.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -74,11 +74,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -90,11 +90,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res index e7ece767..7adc7795 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res @@ -26,11 +26,11 @@ module Internal = { @live let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}`) @live - let fragmentConverterMap = () + let fragmentCallbacks = () @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res index 6934cf8b..406b59f6 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res @@ -53,16 +53,16 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"TestsUtils.Datetime"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"TestsUtils.Number"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"1"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.Datetime": TestsUtils.Datetime.serialize, - "TestsUtils.Number": TestsUtils.Number.serialize, + let variablesCallbacks = { + "0": TestsUtils.Datetime.serialize, + "1": TestsUtils.Number.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -74,11 +74,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["node"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -90,11 +90,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res index b2483d05..4525b34d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res @@ -26,11 +26,11 @@ module Internal = { @live let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}`) @live - let fragmentConverterMap = () + let fragmentCallbacks = () @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res index 3984d6ac..61a9daac 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRelayResolversQuery_graphql.res @@ -31,11 +31,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -47,11 +47,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res index 20b4e246..418152cc 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.res @@ -23,15 +23,15 @@ module Types = { module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["input"],"scalar":"TestsUtils.IntString"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["input"],"scalar":"0"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.IntString": TestsUtils.IntString.serialize, + let variablesCallbacks = { + "0": TestsUtils.IntString.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res index 43b2b5ee..f583b6c1 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.res @@ -20,16 +20,16 @@ module Types = { module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"serializeMultipleCustomScalars"}],"serializeMultipleCustomScalars":[{"list":1,"path":["os1s"],"scalar":"TestsUtils.ObjectScalar1"},{"path":["os2"],"scalar":"TestsUtils.ObjectScalar2"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"serializeMultipleCustomScalars"}],"serializeMultipleCustomScalars":[{"list":1,"path":["os1s"],"scalar":"0"},{"path":["os2"],"scalar":"1"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.ObjectScalar1": TestsUtils.ObjectScalar1.serialize, - "TestsUtils.ObjectScalar2": TestsUtils.ObjectScalar2.serialize, + let variablesCallbacks = { + "0": TestsUtils.ObjectScalar1.serialize, + "1": TestsUtils.ObjectScalar2.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res index 823b33b1..219a0880 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionQuery_graphql.res @@ -31,11 +31,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -47,11 +47,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res index 3bd54b6b..7e265ecc 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.res @@ -35,11 +35,11 @@ module Internal = { @live let responseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["userUpdated","user"]}]},"version":2}`) @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res index 50d7ea2b..b0e9394b 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.res @@ -33,11 +33,11 @@ module Internal = { @live let responseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["userUpdated","user"]}]},"version":2}`) @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res index ca6c8b9c..458fff67 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpersQuery_graphql.res @@ -44,11 +44,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -60,11 +60,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res index 481326d5..8abe5576 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestTestingHelpers_user_graphql.res @@ -19,11 +19,11 @@ module Internal = { @live let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live - let fragmentConverterMap = () + let fragmentCallbacks = () @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res index 125eedbf..1f21e8f4 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragmentQuery_graphql.res @@ -32,11 +32,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["member"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -48,11 +48,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res index fa338fb5..9a6396ef 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_member_graphql.res @@ -30,15 +30,15 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":[],"union":"fragment"},{"fragments":true,"path":["User"]}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":[],"union":"0"},{"fragments":true,"path":["User"]}]},"version":2}`) @live - let fragmentConverterMap = { - "fragment": unwrap_fragment, + let fragmentCallbacks = { + "0": unwrap_fragment, } @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res index 2be7fb63..855323b2 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionFragment_plural_member_graphql.res @@ -31,15 +31,15 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":[],"union":"fragment"},{"fragments":true,"path":["User"]}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":[],"union":"0"},{"fragments":true,"path":["User"]}]},"version":2}`) @live - let fragmentConverterMap = { - "fragment": unwrap_fragment, + let fragmentCallbacks = { + "0": unwrap_fragment, } @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res index ac53d839..64314359 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUnionsQuery_graphql.res @@ -75,16 +75,16 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"response_members_edges_node"},{"list":1,"path":["members","edges","node","Group","members"],"union":"response_members_edges_node_Group_members"}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"0"},{"list":1,"path":["members","edges","node","Group","members"],"union":"1"}]},"version":2}`) @live - let wrapResponseConverterMap = { - "response_members_edges_node_Group_members": wrap_response_members_edges_node_Group_members, - "response_members_edges_node": wrap_response_members_edges_node, + let wrapResponseCallbacks = { + "0": wrap_response_members_edges_node, + "1": wrap_response_members_edges_node_Group_members, } @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -96,14 +96,14 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = { - "response_members_edges_node_Group_members": unwrap_response_members_edges_node_Group_members, - "response_members_edges_node": unwrap_response_members_edges_node, + let responseCallbacks = { + "0": unwrap_response_members_edges_node, + "1": unwrap_response_members_edges_node_Group_members, } @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res index f2af8c68..00e23b3f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.res @@ -32,11 +32,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":[]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -48,11 +48,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res index cc0cf355..e01cebf0 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestUpdatableFragments_query_graphql.res @@ -25,11 +25,11 @@ module Internal = { @live let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live - let fragmentConverterMap = () + let fragmentCallbacks = () @live let preparedFragmentConverter = RescriptRelay.prepareConversion( fragmentConverter, - fragmentConverterMap, + fragmentCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests__/utils-prepared-tests.js b/packages/rescript-relay/__tests__/utils-prepared-tests.js index 42ed7fb3..7e4bb83e 100644 --- a/packages/rescript-relay/__tests__/utils-prepared-tests.js +++ b/packages/rescript-relay/__tests__/utils-prepared-tests.js @@ -598,3 +598,28 @@ describe.each([null, undefined])( }); }, ); + +test("callback slots stay local to each converter and snapshot their bindings", () => { + const schema = object({ number: scalar("0"), text: scalar("1") }); + const callbacks = { 0: (v) => Number(v), 1: (v) => [v] }; + const first = prepare(schema, callbacks); + const second = prepare(schema, { + 0: (v) => Number(v) + 1, + 1: (v) => ({ value: v }), + }); + callbacks[0] = () => 999; + expect(first({ number: "1", text: "a" })).toStrictEqual({ + number: 1, + text: ["a"], + }); + expect(second({ number: "1", text: "a" })).toStrictEqual({ + number: 2, + text: { value: "a" }, + }); + expect(() => prepare(object({ value: scalar("1") }), { 0: Number })).toThrow( + /Missing conversion callback/, + ); + expect(() => prepare(object({ value: scalar("toString") }), {})).toThrow( + /Missing conversion callback/, + ); +}); diff --git a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res index cab3822c..7b725757 100644 --- a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res +++ b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res @@ -49,15 +49,15 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"0"}],"inputC":[{"path":["intStr"],"scalar":"0"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.IntString": TestsUtils.IntString.serialize, + let variablesCallbacks = { + "0": TestsUtils.IntString.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) @@ -69,11 +69,11 @@ module Internal = { @live let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]}]},"version":2}`) @live - let wrapResponseConverterMap = () + let wrapResponseCallbacks = () @live let preparedWrapResponseConverter = RescriptRelay.prepareConversion( wrapResponseConverter, - wrapResponseConverterMap, + wrapResponseCallbacks, null ) ) @@ -85,11 +85,11 @@ module Internal = { @live let responseConverter = wrapResponseConverter @live - let responseConverterMap = () + let responseCallbacks = () @live let preparedResponseConverter = RescriptRelay.prepareConversion( responseConverter, - responseConverterMap, + responseCallbacks, None ) ) diff --git a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res index 760efaa3..03d09104 100644 --- a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res +++ b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.res @@ -15,15 +15,15 @@ module Types = { module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"TestsUtils.IntString"}],"inputC":[{"path":["intStr"],"scalar":"TestsUtils.IntString"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["__relay_internal__pv__ProvidedVariablesInputC"],"reference":"inputC"},{"list":1,"path":["__relay_internal__pv__ProvidedVariablesInputCArr"],"reference":"inputC"},{"path":["__relay_internal__pv__ProvidedVariablesIntStr"],"scalar":"0"}],"inputC":[{"path":["intStr"],"scalar":"0"},{"path":["recursiveC"],"reference":"inputC"}]},"version":2}`) @live - let variablesConverterMap = { - "TestsUtils.IntString": TestsUtils.IntString.serialize, + let variablesCallbacks = { + "0": TestsUtils.IntString.serialize, } @live let preparedVariablesConverter = RescriptRelay.prepareConversion( variablesConverter, - variablesConverterMap, + variablesCallbacks, None ) ) diff --git a/packages/rescript-relay/benchmarks/SIZE.md b/packages/rescript-relay/benchmarks/SIZE.md index e50b673c..03729c9c 100644 --- a/packages/rescript-relay/benchmarks/SIZE.md +++ b/packages/rescript-relay/benchmarks/SIZE.md @@ -17,8 +17,9 @@ measured separately below and must not be counted once per artifact. | Original (`520cac4`) | 284,957 | 37,573 | 26,976 | 119,093 | 106,076 | | First prepared redesign (`e856b90`) | 313,772 | 41,628 | 29,248 | 126,052 | 112,258 | | After size optimization | 277,982 | 36,961 | 26,651 | 119,154 | 105,719 | +| Compact callback IDs | 274,404 | 36,667 | 26,495 | 118,974 | 105,519 | -All numbers are bytes. Relative to the first redesign, this saves 35,790 minified +All numbers are bytes. The first size optimization (before compact callback IDs) saves 35,790 minified bytes / 4,667 gzip bytes in the combined bundle, and 6,898 gzip bytes across the separate bundles. Relative to the original, combined gzip is 612 bytes smaller; separate gzip is 61 bytes larger. These totals do not promise that each individual @@ -62,7 +63,7 @@ the new regression query and schema helper. Use separate worktrees or scratch packages when compiling historical artifacts; do not overwrite current artifacts. Bindings CI checks minified, gzip, and Brotli budgets for both bundle layouts and -uploads the report. Budgets allow 2% headroom over this result. Intentional changes +uploads the report. Budgets now allow 1% headroom over the compact-callback result. Intentional changes to fixture coverage, esbuild version, or budgets need review. The raw reports are `results/size-original.json`, `results/size-before.json`, and `results/size-current.json`. @@ -96,3 +97,35 @@ additional speedup or a reliable regression estimate. Nonempty plans use unchang response traversal code; empty plans reuse that same generic nullable traversal through a shared entry point. Unit, independent-model, mounted, and mutation tests pass. A quieter application benchmark is still needed for precise timing deltas. + +## Compact callback IDs + +The compiler now gives each scalar/union callback a stable, local string ID: + +```js +// Before +{path: ["createdAt"], scalar: "TestsUtils.Datetime"} +// After +{path: ["createdAt"], scalar: "0"} +// The generated callback table still names the function: +{"0": TestsUtils.Datetime.parse} +``` + +Only callback identifiers change. The runtime already resolves string keys in the +callback table during preparation, so there is no runtime change or decoder cost. +Paths, explicit list depth, operation names, and named input references remain +readable and lossless. Scalar/union callbacks occupy distinct slots even if their +names coincide; sorting and deduplication make IDs independent of instruction order. +Slots are scoped to each conversion context, so sharing a plan never shares its +callback bindings between read/write directions or between modules. + +Across the fixed fixture set, literal instruction JSON shrinks from 12,378 to +10,936 bytes (11.6%). Complete generated bundles shrink by another 3,578 minified +bytes, 294 gzip bytes combined, or 180 gzip bytes across separate bundles, versus +`f366d16`. Gzip savings are modest because repeated callback names already compress +well. `results/size-callback-slots.json` is the new full-artifact measurement. + +Experiments with escaped string-path maps and abbreviated operation keys saved +only 77–150 bytes in the combined gzip bundle before decoder costs; they were not +adopted. Indexed callback arrays also produced a worse combined gzip result than +keyed callback tables. The named version 2 protocol remains unchanged. diff --git a/packages/rescript-relay/benchmarks/results/size-callback-slots.json b/packages/rescript-relay/benchmarks/results/size-callback-slots.json new file mode 100644 index 00000000..c61420d6 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-callback-slots.json @@ -0,0 +1,792 @@ +{ + "fixtureVersion": 1, + "esbuild": "0.25.12", + "node": "v24.16.0", + "artifactCount": 129, + "combined": { + "minified": 274404, + "gzip": 36667, + "brotli": 26495 + }, + "separate": { + "minified": 304216, + "gzip": 118974, + "brotli": 105519 + }, + "files": [ + { + "path": "__tests__/__generated__/GroupAvatar_group_graphql.bs.js", + "minified": 711, + "gzip": 447, + "brotli": 384 + }, + { + "path": "__tests__/__generated__/HasNameComponent_hasName_graphql.bs.js", + "minified": 805, + "gzip": 467, + "brotli": 400 + }, + { + "path": "__tests__/__generated__/LocalUser____relay_model_instance_graphql.bs.js", + "minified": 1059, + "gzip": 579, + "brotli": 506 + }, + { + "path": "__tests__/__generated__/LocalUser__id_graphql.bs.js", + "minified": 747, + "gzip": 462, + "brotli": 399 + }, + { + "path": "__tests__/__generated__/LocalUser_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/Query_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/RichContent_content_graphql.bs.js", + "minified": 722, + "gzip": 447, + "brotli": 380 + }, + { + "path": "__tests__/__generated__/TestAliasedFragmentsQuery_graphql.bs.js", + "minified": 3136, + "gzip": 1125, + "brotli": 1003 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.bs.js", + "minified": 732, + "gzip": 455, + "brotli": 394 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userLastName_graphql.bs.js", + "minified": 730, + "gzip": 454, + "brotli": 391 + }, + { + "path": "__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.bs.js", + "minified": 2930, + "gzip": 1217, + "brotli": 1073 + }, + { + "path": "__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.bs.js", + "minified": 2721, + "gzip": 1165, + "brotli": 1035 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.bs.js", + "minified": 3889, + "gzip": 1386, + "brotli": 1260 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropQuery_graphql.bs.js", + "minified": 3020, + "gzip": 1285, + "brotli": 1159 + }, + { + "path": "__tests__/__generated__/TestCatchMembersPropQuery_graphql.bs.js", + "minified": 3708, + "gzip": 1381, + "brotli": 1244 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMemberQuery_graphql.bs.js", + "minified": 3073, + "gzip": 1217, + "brotli": 1078 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMember_member_graphql.bs.js", + "minified": 1472, + "gzip": 691, + "brotli": 604 + }, + { + "path": "__tests__/__generated__/TestCatchUser_user_graphql.bs.js", + "minified": 875, + "gzip": 542, + "brotli": 465 + }, + { + "path": "__tests__/__generated__/TestCodesplitQuery_graphql.bs.js", + "minified": 7005, + "gzip": 1782, + "brotli": 1615 + }, + { + "path": "__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.bs.js", + "minified": 731, + "gzip": 458, + "brotli": 393 + }, + { + "path": "__tests__/__generated__/TestConnections2_user_graphql.bs.js", + "minified": 4067, + "gzip": 1345, + "brotli": 1220 + }, + { + "path": "__tests__/__generated__/TestConnections3_user_graphql.bs.js", + "minified": 2334, + "gzip": 860, + "brotli": 766 + }, + { + "path": "__tests__/__generated__/TestConnectionsQuery_graphql.bs.js", + "minified": 4183, + "gzip": 1508, + "brotli": 1348 + }, + { + "path": "__tests__/__generated__/TestConnections_AddFriendMutation_graphql.bs.js", + "minified": 2252, + "gzip": 914, + "brotli": 809 + }, + { + "path": "__tests__/__generated__/TestConnections_user_graphql.bs.js", + "minified": 2999, + "gzip": 1075, + "brotli": 966 + }, + { + "path": "__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2616, + "gzip": 1119, + "brotli": 992 + }, + { + "path": "__tests__/__generated__/TestCustomScalarsQuery_graphql.bs.js", + "minified": 4182, + "gzip": 1475, + "brotli": 1336 + }, + { + "path": "__tests__/__generated__/TestFragmentQuery_graphql.bs.js", + "minified": 4301, + "gzip": 1367, + "brotli": 1223 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.bs.js", + "minified": 903, + "gzip": 534, + "brotli": 463 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredQuery_graphql.bs.js", + "minified": 3467, + "gzip": 1182, + "brotli": 1050 + }, + { + "path": "__tests__/__generated__/TestFragmentRequired_user_graphql.bs.js", + "minified": 890, + "gzip": 525, + "brotli": 452 + }, + { + "path": "__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.bs.js", + "minified": 925, + "gzip": 524, + "brotli": 451 + }, + { + "path": "__tests__/__generated__/TestFragment_inline_graphql.bs.js", + "minified": 694, + "gzip": 430, + "brotli": 372 + }, + { + "path": "__tests__/__generated__/TestFragment_plural_user_graphql.bs.js", + "minified": 996, + "gzip": 531, + "brotli": 458 + }, + { + "path": "__tests__/__generated__/TestFragment_sub_user_graphql.bs.js", + "minified": 718, + "gzip": 450, + "brotli": 387 + }, + { + "path": "__tests__/__generated__/TestFragment_user_graphql.bs.js", + "minified": 1168, + "gzip": 600, + "brotli": 513 + }, + { + "path": "__tests__/__generated__/TestInputUnionQuery_graphql.bs.js", + "minified": 2163, + "gzip": 1037, + "brotli": 904 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadQuery_graphql.bs.js", + "minified": 5054, + "gzip": 1560, + "brotli": 1408 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.bs.js", + "minified": 5686, + "gzip": 1693, + "brotli": 1525 + }, + { + "path": "__tests__/__generated__/TestLocalPayload_user_graphql.bs.js", + "minified": 2408, + "gzip": 847, + "brotli": 753 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.bs.js", + "minified": 2185, + "gzip": 961, + "brotli": 844 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.bs.js", + "minified": 2708, + "gzip": 1169, + "brotli": 1043 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.bs.js", + "minified": 2337, + "gzip": 1033, + "brotli": 913 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.bs.js", + "minified": 2325, + "gzip": 1033, + "brotli": 911 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.bs.js", + "minified": 2183, + "gzip": 956, + "brotli": 844 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.bs.js", + "minified": 2704, + "gzip": 1167, + "brotli": 1040 + }, + { + "path": "__tests__/__generated__/TestMutationInline_user_graphql.bs.js", + "minified": 698, + "gzip": 434, + "brotli": 376 + }, + { + "path": "__tests__/__generated__/TestMutationProvidedVariable_user_graphql.bs.js", + "minified": 898, + "gzip": 514, + "brotli": 443 + }, + { + "path": "__tests__/__generated__/TestMutationQuery_graphql.bs.js", + "minified": 3201, + "gzip": 1208, + "brotli": 1066 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.bs.js", + "minified": 2404, + "gzip": 990, + "brotli": 882 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.bs.js", + "minified": 2994, + "gzip": 1025, + "brotli": 923 + }, + { + "path": "__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 2929, + "gzip": 1004, + "brotli": 900 + }, + { + "path": "__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 3910, + "gzip": 1231, + "brotli": 1116 + }, + { + "path": "__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.bs.js", + "minified": 2788, + "gzip": 967, + "brotli": 880 + }, + { + "path": "__tests__/__generated__/TestMutation_user_graphql.bs.js", + "minified": 1757, + "gzip": 732, + "brotli": 645 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.bs.js", + "minified": 3137, + "gzip": 1238, + "brotli": 1103 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceQuery_graphql.bs.js", + "minified": 3720, + "gzip": 1318, + "brotli": 1193 + }, + { + "path": "__tests__/__generated__/TestNodeInterface_user_graphql.bs.js", + "minified": 720, + "gzip": 454, + "brotli": 387 + }, + { + "path": "__tests__/__generated__/TestNonReactQuery_graphql.bs.js", + "minified": 2468, + "gzip": 1077, + "brotli": 944 + }, + { + "path": "__tests__/__generated__/TestNonReact_user_graphql.bs.js", + "minified": 914, + "gzip": 519, + "brotli": 447 + }, + { + "path": "__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2798, + "gzip": 1170, + "brotli": 1035 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesMutation_graphql.bs.js", + "minified": 2713, + "gzip": 1016, + "brotli": 908 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesQuery_graphql.bs.js", + "minified": 2141, + "gzip": 948, + "brotli": 834 + }, + { + "path": "__tests__/__generated__/TestObserverQuery_graphql.bs.js", + "minified": 1893, + "gzip": 922, + "brotli": 813 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeQuery_graphql.bs.js", + "minified": 4371, + "gzip": 1458, + "brotli": 1305 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.bs.js", + "minified": 5073, + "gzip": 1630, + "brotli": 1473 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_query_graphql.bs.js", + "minified": 2756, + "gzip": 1055, + "brotli": 940 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_user_graphql.bs.js", + "minified": 1062, + "gzip": 549, + "brotli": 475 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionQuery_graphql.bs.js", + "minified": 4940, + "gzip": 1564, + "brotli": 1406 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.bs.js", + "minified": 5708, + "gzip": 1728, + "brotli": 1559 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_query_graphql.bs.js", + "minified": 3817, + "gzip": 1250, + "brotli": 1122 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_user_graphql.bs.js", + "minified": 993, + "gzip": 541, + "brotli": 471 + }, + { + "path": "__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.bs.js", + "minified": 2767, + "gzip": 1117, + "brotli": 994 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.bs.js", + "minified": 3657, + "gzip": 1295, + "brotli": 1149 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.bs.js", + "minified": 4215, + "gzip": 1439, + "brotli": 1293 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.bs.js", + "minified": 1106, + "gzip": 555, + "brotli": 486 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user_graphql.bs.js", + "minified": 2208, + "gzip": 879, + "brotli": 776 + }, + { + "path": "__tests__/__generated__/TestProvidedVariablesQuery_graphql.bs.js", + "minified": 5647, + "gzip": 1538, + "brotli": 1388 + }, + { + "path": "__tests__/__generated__/TestProvidedVariables_user_graphql.bs.js", + "minified": 1581, + "gzip": 572, + "brotli": 504 + }, + { + "path": "__tests__/__generated__/TestQueryInputObjectsQuery_graphql.bs.js", + "minified": 2084, + "gzip": 1030, + "brotli": 911 + }, + { + "path": "__tests__/__generated__/TestQuery_graphql.bs.js", + "minified": 2742, + "gzip": 1179, + "brotli": 1068 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeQuery_graphql.bs.js", + "minified": 3807, + "gzip": 1422, + "brotli": 1280 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.bs.js", + "minified": 3912, + "gzip": 1420, + "brotli": 1275 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNode_user_graphql.bs.js", + "minified": 1705, + "gzip": 769, + "brotli": 668 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.bs.js", + "minified": 2193, + "gzip": 1016, + "brotli": 902 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgs_query_graphql.bs.js", + "minified": 988, + "gzip": 558, + "brotli": 485 + }, + { + "path": "__tests__/__generated__/TestRefetchingQuery_graphql.bs.js", + "minified": 3719, + "gzip": 1387, + "brotli": 1234 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.bs.js", + "minified": 2235, + "gzip": 1022, + "brotli": 905 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.bs.js", + "minified": 1000, + "gzip": 561, + "brotli": 489 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordQuery_graphql.bs.js", + "minified": 3761, + "gzip": 1393, + "brotli": 1240 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.bs.js", + "minified": 4554, + "gzip": 1593, + "brotli": 1439 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecord_user_graphql.bs.js", + "minified": 2166, + "gzip": 874, + "brotli": 768 + }, + { + "path": "__tests__/__generated__/TestRefetchingRefetchQuery_graphql.bs.js", + "minified": 4512, + "gzip": 1589, + "brotli": 1434 + }, + { + "path": "__tests__/__generated__/TestRefetching_user_graphql.bs.js", + "minified": 2154, + "gzip": 870, + "brotli": 765 + }, + { + "path": "__tests__/__generated__/TestRelayResolversAllQuery_graphql.bs.js", + "minified": 5361, + "gzip": 1536, + "brotli": 1386 + }, + { + "path": "__tests__/__generated__/TestRelayResolversQuery_graphql.bs.js", + "minified": 3046, + "gzip": 1181, + "brotli": 1052 + }, + { + "path": "__tests__/__generated__/TestRelayResolvers_user_graphql.bs.js", + "minified": 1300, + "gzip": 625, + "brotli": 542 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver2_graphql.bs.js", + "minified": 794, + "gzip": 465, + "brotli": 395 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver_graphql.bs.js", + "minified": 793, + "gzip": 463, + "brotli": 395 + }, + { + "path": "__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.bs.js", + "minified": 2191, + "gzip": 967, + "brotli": 855 + }, + { + "path": "__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.bs.js", + "minified": 1796, + "gzip": 841, + "brotli": 735 + }, + { + "path": "__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.bs.js", + "minified": 1829, + "gzip": 827, + "brotli": 719 + }, + { + "path": "__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.bs.js", + "minified": 902, + "gzip": 515, + "brotli": 443 + }, + { + "path": "__tests__/__generated__/TestSubscriptionQuery_graphql.bs.js", + "minified": 2542, + "gzip": 1073, + "brotli": 942 + }, + { + "path": "__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.bs.js", + "minified": 2552, + "gzip": 952, + "brotli": 837 + }, + { + "path": "__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.bs.js", + "minified": 3038, + "gzip": 1066, + "brotli": 953 + }, + { + "path": "__tests__/__generated__/TestSubscription_user_graphql.bs.js", + "minified": 1061, + "gzip": 535, + "brotli": 455 + }, + { + "path": "__tests__/__generated__/TestTestingHelpersQuery_graphql.bs.js", + "minified": 3448, + "gzip": 1298, + "brotli": 1170 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_plural_user_graphql.bs.js", + "minified": 1002, + "gzip": 538, + "brotli": 466 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_sub_user_graphql.bs.js", + "minified": 724, + "gzip": 458, + "brotli": 390 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_user_graphql.bs.js", + "minified": 1180, + "gzip": 607, + "brotli": 521 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentQuery_graphql.bs.js", + "minified": 3556, + "gzip": 1264, + "brotli": 1124 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentUser_user_graphql.bs.js", + "minified": 923, + "gzip": 520, + "brotli": 448 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_member_graphql.bs.js", + "minified": 1547, + "gzip": 696, + "brotli": 609 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_plural_member_graphql.bs.js", + "minified": 1561, + "gzip": 707, + "brotli": 634 + }, + { + "path": "__tests__/__generated__/TestUnionsQuery_graphql.bs.js", + "minified": 5037, + "gzip": 1522, + "brotli": 1380 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.bs.js", + "minified": 2816, + "gzip": 1121, + "brotli": 997 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_query_graphql.bs.js", + "minified": 1248, + "gzip": 607, + "brotli": 517 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_updatableUser_graphql.bs.js", + "minified": 678, + "gzip": 363, + "brotli": 321 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.bs.js", + "minified": 1298, + "gzip": 610, + "brotli": 529 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_graphql.bs.js", + "minified": 2607, + "gzip": 1046, + "brotli": 936 + }, + { + "path": "__tests__/__generated__/UserAvatar_user_graphql.bs.js", + "minified": 1049, + "gzip": 572, + "brotli": 494 + }, + { + "path": "__tests__/__generated__/UserMeta____relay_model_instance_graphql.bs.js", + "minified": 785, + "gzip": 476, + "brotli": 404 + }, + { + "path": "__tests__/__generated__/UserMeta_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/UserName_user_graphql.bs.js", + "minified": 785, + "gzip": 458, + "brotli": 393 + }, + { + "path": "__tests__/__generated__/User_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.bs.js", + "minified": 1418, + "gzip": 570, + "brotli": 499 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.bs.js", + "minified": 5083, + "gzip": 1495, + "brotli": 1342 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.bs.js", + "minified": 2236, + "gzip": 845, + "brotli": 759 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/size-budgets.json b/packages/rescript-relay/benchmarks/size-budgets.json index 09a95d8b..493dc776 100644 --- a/packages/rescript-relay/benchmarks/size-budgets.json +++ b/packages/rescript-relay/benchmarks/size-budgets.json @@ -1,12 +1,12 @@ { "combined": { - "minified": 283542, - "gzip": 37700, - "brotli": 27184 + "minified": 277148, + "gzip": 37034, + "brotli": 26760 }, "separate": { - "minified": 313950, - "gzip": 121537, - "brotli": 107833 + "minified": 307258, + "gzip": 120164, + "brotli": 106574 } } diff --git a/packages/rescript-relay/docs/conversion-contract.md b/packages/rescript-relay/docs/conversion-contract.md index 0746e62e..4da19fcf 100644 --- a/packages/rescript-relay/docs/conversion-contract.md +++ b/packages/rescript-relay/docs/conversion-contract.md @@ -120,3 +120,9 @@ separate. Empty plans reuse the runtime's callback-free nullable converter, whic retains neither inputs nor application callbacks. The named version 2 plan format and response semantics are unchanged. See [size measurements](../benchmarks/SIZE.md) for complete generated-artifact bundles, separate gzip/Brotli totals, and CI budgets. + +Compiler-generated callback keys may be short string IDs such as `"0"`. They are +local to a conversion's callback table, assigned deterministically across scalar +and union callbacks, and do not change response traversal. Public preparation +still accepts named callback keys. Plans may be shared, but callback bindings are +always prepared against their own table and snapshotted independently. From b0f009a9ad97dbdf89c1c631e3c11c51d480ab0d Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 09:36:44 +0200 Subject: [PATCH 09/23] Drop redundant native-list plans and retain required conversion boundaries --- packages/relay | 2 +- ...ayUnderlyingScalarSiblingQuery_graphql.res | 28 +- .../TestConnections2_user_graphql.res | 2 +- .../TestConnections3_user_graphql.res | 14 +- ...tConnections_AddFriendMutation_graphql.res | 14 +- .../TestConnections_user_graphql.res | 14 +- ...ieldHandlersPluralBestiesQuery_graphql.res | 28 +- ...issingFieldHandlersPluralQuery_graphql.res | 28 +- ...stPaginationInNodeRefetchQuery_graphql.res | 14 +- ...estPaginationUnionRefetchQuery_graphql.res | 14 +- .../TestPaginationUnion_query_graphql.res | 2 +- ...estParseCustomScalarArrayQuery_graphql.res | 2 +- .../TestQueryInputObjectsQuery_graphql.res | 2 +- .../__generated__/TestQuery_graphql.res | 28 +- .../TestRefetchingInNodeQuery_graphql.res | 14 +- ...stRefetchingInNodeRefetchQuery_graphql.res | 14 +- ...stRefetchingRecordRefetchQuery_graphql.res | 2 +- .../TestRefetchingRecord_user_graphql.res | 14 +- .../TestRefetchingRefetchQuery_graphql.res | 2 +- .../TestRefetching_user_graphql.res | 14 +- .../__tests__/utils-prepared-tests.js | 44 + .../TestPreloadedQuery_graphql.res | 2 +- packages/rescript-relay/benchmarks/SIZE.md | 30 +- .../benchmarks/results/size-pruned-lists.json | 792 ++++++++++++++++++ .../benchmarks/size-budgets.json | 12 +- .../docs/conversion-contract.md | 6 + 26 files changed, 902 insertions(+), 236 deletions(-) create mode 100644 packages/rescript-relay/benchmarks/results/size-pruned-lists.json diff --git a/packages/relay b/packages/relay index 6cb6cee5..bd305ebb 160000 --- a/packages/relay +++ b/packages/relay @@ -1 +1 @@ -Subproject commit 6cb6cee5a4d0ff0e9d2d0aad37214e46cce19209 +Subproject commit bd305ebbc23b054dd8d59dbf27218a6dbd174c3a diff --git a/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res index b53670cb..93c398d3 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.res @@ -58,36 +58,12 @@ module Internal = { let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) @live type wrapResponseRaw - %%private( - @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friends"]}]},"version":2}`) @live - let wrapResponseCallbacks = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseCallbacks, - null - ) - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw - %%private( - @live - let responseConverter = wrapResponseConverter - @live - let responseCallbacks = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseCallbacks, - None - ) - ) @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res index 5d68ec80..e0438d96 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections2_user_graphql.res @@ -35,7 +35,7 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member"],"union":"0"},{"list":1,"path":["member","User","friendsConnection","edges"]}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["member"],"union":"0"}]},"version":2}`) @live let fragmentCallbacks = { "0": unwrap_fragment_member, diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res index 8dc4016d..848bab61 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections3_user_graphql.res @@ -24,20 +24,8 @@ module Types = { module Internal = { @live type fragmentRaw - %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["loggedInUser","friendsConnection","edges"]}]},"version":2}`) - @live - let fragmentCallbacks = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentCallbacks, - None - ) - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res index e61bfb83..3df79eb4 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections_AddFriendMutation_graphql.res @@ -26,20 +26,8 @@ module Types = { } module Internal = { - %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["connections"]}]},"version":2}`) - @live - let variablesCallbacks = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesCallbacks, - None - ) - ) - @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw @live diff --git a/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res index 73a1701e..3a9f1149 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConnections_user_graphql.res @@ -22,20 +22,8 @@ module Types = { module Internal = { @live type fragmentRaw - %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsConnection","edges"]}]},"version":2}`) - @live - let fragmentCallbacks = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentCallbacks, - None - ) - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res index 9520cd48..80c2f639 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.res @@ -27,36 +27,12 @@ module Internal = { let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw - %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["onlineBesties"]}]},"version":2}`) - @live - let wrapResponseCallbacks = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseCallbacks, - null - ) - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw - %%private( - @live - let responseConverter = wrapResponseConverter - @live - let responseCallbacks = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseCallbacks, - None - ) - ) @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res index c1ba5ec2..c9b438dd 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.res @@ -27,36 +27,12 @@ module Internal = { let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw - %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["topOnlineUserList"]}]},"version":2}`) - @live - let wrapResponseCallbacks = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseCallbacks, - null - ) - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw - %%private( - @live - let responseConverter = wrapResponseConverter - @live - let responseCallbacks = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseCallbacks, - None - ) - ) @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res index b383411d..bdf6e0f8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.res @@ -47,20 +47,8 @@ module Types = { type queryRef module Internal = { - %%private( - @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}`) - @live - let variablesCallbacks = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesCallbacks, - None - ) - ) @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw %%private( diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res index 4799c026..3034b9ad 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.res @@ -42,20 +42,8 @@ module Types = { type queryRef module Internal = { - %%private( - @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["onlineStatuses"]}]},"version":2}`) - @live - let variablesCallbacks = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesCallbacks, - None - ) - ) @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw %%private( diff --git a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res index 42448a74..7fdf2e3f 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestPaginationUnion_query_graphql.res @@ -50,7 +50,7 @@ module Internal = { type fragmentRaw %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"0"},{"list":1,"path":["members","edges","node","Group","adminsConnection","edges"]},{"fragments":true,"path":["members","edges","node","User"]}]},"version":2}`) + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"path":["members","edges","node"],"union":"0"},{"fragments":true,"path":["members","edges","node","User"]}]},"version":2}`) @live let fragmentCallbacks = { "0": unwrap_fragment_members_edges_node, diff --git a/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res index 5dea813a..371aa62d 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.res @@ -32,7 +32,7 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","intString"],"scalar":"0"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"0"},{"list":1,"path":["loggedInUser","justStrings"]}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["loggedInUser","intString"],"scalar":"0"},{"list":1,"path":["loggedInUser","intStrings"],"scalar":"0"}]},"version":2}`) @live let wrapResponseCallbacks = { "0": TestsUtils.IntString.serialize, diff --git a/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res index db17e25a..537772f8 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestQueryInputObjectsQuery_graphql.res @@ -32,7 +32,7 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"searchInput"}],"searchInput":[{"list":1,"path":["names"]}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"searchInput"}],"searchInput":[]},"version":2}`) @live let variablesCallbacks = () @live diff --git a/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res index a55ac2ce..e97fdd48 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestQuery_graphql.res @@ -44,36 +44,12 @@ module Internal = { let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw - %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["users","edges"]}]},"version":2}`) - @live - let wrapResponseCallbacks = () - @live - let preparedWrapResponseConverter = RescriptRelay.prepareConversion( - wrapResponseConverter, - wrapResponseCallbacks, - null - ) - ) - @live - let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + let convertWrapResponse = value => RescriptRelay.convertWithoutPlan(value, null) @live type responseRaw - %%private( - @live - let responseConverter = wrapResponseConverter - @live - let responseCallbacks = () - @live - let preparedResponseConverter = RescriptRelay.prepareConversion( - responseConverter, - responseCallbacks, - None - ) - ) @live - let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + let convertResponse = value => RescriptRelay.convertWithoutPlan(value, None) type wrapRawResponseRaw = wrapResponseRaw @live let convertWrapRawResponse = convertWrapResponse diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res index d01e9202..d2bcbfd1 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeQuery_graphql.res @@ -45,20 +45,8 @@ let wrap_response_node: Types.response_node => Types.response_node = RescriptRel type queryRef module Internal = { - %%private( - @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}`) - @live - let variablesCallbacks = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesCallbacks, - None - ) - ) @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw %%private( diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res index 8eaf5d2e..0fb39398 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.res @@ -43,20 +43,8 @@ module Types = { type queryRef module Internal = { - %%private( - @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friendsOnlineStatuses"]}]},"version":2}`) - @live - let variablesCallbacks = () - @live - let preparedVariablesConverter = RescriptRelay.prepareConversion( - variablesConverter, - variablesCallbacks, - None - ) - ) @live - let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) @live type wrapResponseRaw %%private( diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res index a4eb8ac8..2f89987c 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.res @@ -53,7 +53,7 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"1"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"},{"path":["number"],"scalar":"1"}]},"version":2}`) @live let variablesCallbacks = { "0": TestsUtils.Datetime.serialize, diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res index 7adc7795..ac906753 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRecord_user_graphql.res @@ -22,20 +22,8 @@ module Types = { module Internal = { @live type fragmentRaw - %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}`) - @live - let fragmentCallbacks = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentCallbacks, - None - ) - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res index 406b59f6..29914aa7 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetchingRefetchQuery_graphql.res @@ -53,7 +53,7 @@ type queryRef module Internal = { %%private( @live - let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"},{"list":1,"path":["friendsOnlineStatuses"]},{"path":["number"],"scalar":"1"}]},"version":2}`) + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["beforeDate"],"scalar":"0"},{"path":["number"],"scalar":"1"}]},"version":2}`) @live let variablesCallbacks = { "0": TestsUtils.Datetime.serialize, diff --git a/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res index 4525b34d..2c2b75eb 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestRefetching_user_graphql.res @@ -22,20 +22,8 @@ module Types = { module Internal = { @live type fragmentRaw - %%private( @live - let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["friends"]}]},"version":2}`) - @live - let fragmentCallbacks = () - @live - let preparedFragmentConverter = RescriptRelay.prepareConversion( - fragmentConverter, - fragmentCallbacks, - None - ) - ) - @live - let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) + let convertFragment = value => RescriptRelay.convertWithoutPlan(value, None) } type t diff --git a/packages/rescript-relay/__tests__/utils-prepared-tests.js b/packages/rescript-relay/__tests__/utils-prepared-tests.js index 7e4bb83e..4877d523 100644 --- a/packages/rescript-relay/__tests__/utils-prepared-tests.js +++ b/packages/rescript-relay/__tests__/utils-prepared-tests.js @@ -623,3 +623,47 @@ test("callback slots stay local to each converter and snapshot their bindings", /Missing conversion callback/, ); }); + +describe.each([null, undefined])( + "omitted native-list hints (nullable=%s)", + (nullable) => { + test.each([1, 2, 3])( + "preserves native values, holes and nullable wrappers at depth %i", + (depth) => { + const { convertWithoutPlan } = require("../src/utils"); + let values = [ + 0, + false, + "", + null, + undefined, + , + { BS_PRIVATE_NESTED_SOME_NONE: 0 }, + ]; + let schema = list(scalar("identity")); + for (let i = 1; i < depth; i++) { + values = [values, null, undefined, , []]; + schema = list(schema); + } + const input = freeze({ values, __metadata: { opaque: null } }); + const expected = evaluate( + object({ values: schema }), + input, + {}, + { identity: (value) => value }, + nullable, + ); + const explicit = prepareConversion( + { + version: 2, + roots: { __root: [{ path: ["values"], list: depth }] }, + }, + undefined, + nullable, + ); + expect(explicit(input)).toStrictEqual(expected); + expect(convertWithoutPlan(input, nullable)).toStrictEqual(expected); + }, + ); + }, +); diff --git a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res index 7b725757..6c609e95 100644 --- a/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res +++ b/packages/rescript-relay/__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.res @@ -67,7 +67,7 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]},{"list":1,"path":["users","edges"]}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"fragments":true,"path":["loggedInUser"]}]},"version":2}`) @live let wrapResponseCallbacks = () @live diff --git a/packages/rescript-relay/benchmarks/SIZE.md b/packages/rescript-relay/benchmarks/SIZE.md index 03729c9c..26f489db 100644 --- a/packages/rescript-relay/benchmarks/SIZE.md +++ b/packages/rescript-relay/benchmarks/SIZE.md @@ -18,6 +18,7 @@ measured separately below and must not be counted once per artifact. | First prepared redesign (`e856b90`) | 313,772 | 41,628 | 29,248 | 126,052 | 112,258 | | After size optimization | 277,982 | 36,961 | 26,651 | 119,154 | 105,719 | | Compact callback IDs | 274,404 | 36,667 | 26,495 | 118,974 | 105,519 | +| Pruned plain-list hints | 272,639 | 36,319 | 26,233 | 118,381 | 104,973 | All numbers are bytes. The first size optimization (before compact callback IDs) saves 35,790 minified bytes / 4,667 gzip bytes in the combined bundle, and 6,898 gzip bytes across the @@ -63,7 +64,7 @@ the new regression query and schema helper. Use separate worktrees or scratch packages when compiling historical artifacts; do not overwrite current artifacts. Bindings CI checks minified, gzip, and Brotli budgets for both bundle layouts and -uploads the report. Budgets now allow 1% headroom over the compact-callback result. Intentional changes +uploads the report. Budgets now allow 1% headroom over the pruned-list result. Intentional changes to fixture coverage, esbuild version, or budgets need review. The raw reports are `results/size-original.json`, `results/size-before.json`, and `results/size-current.json`. @@ -129,3 +130,30 @@ Experiments with escaped string-path maps and abbreviated operation keys saved only 77–150 bytes in the combined gzip bundle before decoder costs; they were not adopted. Indexed callback arrays also produced a worse combined gzip result than keyed callback tables. The named version 2 protocol remains unchanged. + +## Final pass: omit redundant native-list hints + +A list instruction is unnecessary when there is no scalar/union/reference/opaque/ +fragment operation at or below its path. The generic converter already traverses +plain lists and normalizes nullability. The compiler now omits those hints. When +this leaves an empty root plan, it emits the existing shared-converter call and +omits the per-artifact plan and prepared handle as well. + +Required list depths are retained, including ancestors of special conversions; +path comparisons use full segments, so `a_b` cannot be confused with `a.b`. Named +input references remain explicit even when their target only needs normalization, +because they can also unwrap input unions. Neither the protocol nor runtime code +changes. + +Relative to compact callback IDs (`3a55220`), this saves another **1,765 minified +bytes / 348 gzip bytes combined**, or **593 gzip bytes across separate bundles**. +The final fixture bundles are smaller than original master by 1,254 gzip bytes +combined and 712 gzip bytes separately, excluding the shared runtime and external +dependencies as before. `results/size-pruned-lists.json` records the complete result. + +Compiler tests cover every retained operation boundary and omission of irrelevant +siblings/ancestors. JS tests compare omitted versus explicit native-list hints to +an independent evaluator at depths 1–3 in both nullable directions, including +sparse arrays, option markers, and falsey values. The full mounted suite also uses +the regenerated artifacts. More elaborate format compression was intentionally +left out. diff --git a/packages/rescript-relay/benchmarks/results/size-pruned-lists.json b/packages/rescript-relay/benchmarks/results/size-pruned-lists.json new file mode 100644 index 00000000..44689418 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/size-pruned-lists.json @@ -0,0 +1,792 @@ +{ + "fixtureVersion": 1, + "esbuild": "0.25.12", + "node": "v24.16.0", + "artifactCount": 129, + "combined": { + "minified": 272639, + "gzip": 36319, + "brotli": 26233 + }, + "separate": { + "minified": 302536, + "gzip": 118381, + "brotli": 104973 + }, + "files": [ + { + "path": "__tests__/__generated__/GroupAvatar_group_graphql.bs.js", + "minified": 711, + "gzip": 447, + "brotli": 384 + }, + { + "path": "__tests__/__generated__/HasNameComponent_hasName_graphql.bs.js", + "minified": 805, + "gzip": 467, + "brotli": 400 + }, + { + "path": "__tests__/__generated__/LocalUser____relay_model_instance_graphql.bs.js", + "minified": 1059, + "gzip": 579, + "brotli": 506 + }, + { + "path": "__tests__/__generated__/LocalUser__id_graphql.bs.js", + "minified": 747, + "gzip": 462, + "brotli": 399 + }, + { + "path": "__tests__/__generated__/LocalUser_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/Query_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/RichContent_content_graphql.bs.js", + "minified": 722, + "gzip": 447, + "brotli": 380 + }, + { + "path": "__tests__/__generated__/TestAliasedFragmentsQuery_graphql.bs.js", + "minified": 3136, + "gzip": 1125, + "brotli": 1003 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.bs.js", + "minified": 732, + "gzip": 455, + "brotli": 394 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userLastName_graphql.bs.js", + "minified": 730, + "gzip": 454, + "brotli": 391 + }, + { + "path": "__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.bs.js", + "minified": 2792, + "gzip": 1191, + "brotli": 1066 + }, + { + "path": "__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.bs.js", + "minified": 2721, + "gzip": 1165, + "brotli": 1035 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.bs.js", + "minified": 3889, + "gzip": 1386, + "brotli": 1260 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropQuery_graphql.bs.js", + "minified": 3020, + "gzip": 1285, + "brotli": 1159 + }, + { + "path": "__tests__/__generated__/TestCatchMembersPropQuery_graphql.bs.js", + "minified": 3708, + "gzip": 1381, + "brotli": 1244 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMemberQuery_graphql.bs.js", + "minified": 3073, + "gzip": 1217, + "brotli": 1078 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMember_member_graphql.bs.js", + "minified": 1472, + "gzip": 691, + "brotli": 604 + }, + { + "path": "__tests__/__generated__/TestCatchUser_user_graphql.bs.js", + "minified": 875, + "gzip": 542, + "brotli": 465 + }, + { + "path": "__tests__/__generated__/TestCodesplitQuery_graphql.bs.js", + "minified": 7005, + "gzip": 1782, + "brotli": 1615 + }, + { + "path": "__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.bs.js", + "minified": 731, + "gzip": 458, + "brotli": 393 + }, + { + "path": "__tests__/__generated__/TestConnections2_user_graphql.bs.js", + "minified": 4007, + "gzip": 1328, + "brotli": 1202 + }, + { + "path": "__tests__/__generated__/TestConnections3_user_graphql.bs.js", + "minified": 2215, + "gzip": 817, + "brotli": 726 + }, + { + "path": "__tests__/__generated__/TestConnectionsQuery_graphql.bs.js", + "minified": 4183, + "gzip": 1508, + "brotli": 1348 + }, + { + "path": "__tests__/__generated__/TestConnections_AddFriendMutation_graphql.bs.js", + "minified": 2162, + "gzip": 856, + "brotli": 771 + }, + { + "path": "__tests__/__generated__/TestConnections_user_graphql.bs.js", + "minified": 2895, + "gzip": 1031, + "brotli": 928 + }, + { + "path": "__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2616, + "gzip": 1119, + "brotli": 992 + }, + { + "path": "__tests__/__generated__/TestCustomScalarsQuery_graphql.bs.js", + "minified": 4182, + "gzip": 1475, + "brotli": 1336 + }, + { + "path": "__tests__/__generated__/TestFragmentQuery_graphql.bs.js", + "minified": 4301, + "gzip": 1367, + "brotli": 1223 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.bs.js", + "minified": 903, + "gzip": 534, + "brotli": 463 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredQuery_graphql.bs.js", + "minified": 3467, + "gzip": 1182, + "brotli": 1050 + }, + { + "path": "__tests__/__generated__/TestFragmentRequired_user_graphql.bs.js", + "minified": 890, + "gzip": 525, + "brotli": 452 + }, + { + "path": "__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.bs.js", + "minified": 925, + "gzip": 524, + "brotli": 451 + }, + { + "path": "__tests__/__generated__/TestFragment_inline_graphql.bs.js", + "minified": 694, + "gzip": 430, + "brotli": 372 + }, + { + "path": "__tests__/__generated__/TestFragment_plural_user_graphql.bs.js", + "minified": 996, + "gzip": 531, + "brotli": 458 + }, + { + "path": "__tests__/__generated__/TestFragment_sub_user_graphql.bs.js", + "minified": 718, + "gzip": 450, + "brotli": 387 + }, + { + "path": "__tests__/__generated__/TestFragment_user_graphql.bs.js", + "minified": 1168, + "gzip": 600, + "brotli": 513 + }, + { + "path": "__tests__/__generated__/TestInputUnionQuery_graphql.bs.js", + "minified": 2163, + "gzip": 1037, + "brotli": 904 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadQuery_graphql.bs.js", + "minified": 5054, + "gzip": 1560, + "brotli": 1408 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.bs.js", + "minified": 5686, + "gzip": 1693, + "brotli": 1525 + }, + { + "path": "__tests__/__generated__/TestLocalPayload_user_graphql.bs.js", + "minified": 2408, + "gzip": 847, + "brotli": 753 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.bs.js", + "minified": 2185, + "gzip": 961, + "brotli": 844 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.bs.js", + "minified": 2708, + "gzip": 1169, + "brotli": 1043 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.bs.js", + "minified": 2208, + "gzip": 963, + "brotli": 846 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.bs.js", + "minified": 2192, + "gzip": 963, + "brotli": 843 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.bs.js", + "minified": 2183, + "gzip": 956, + "brotli": 844 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.bs.js", + "minified": 2704, + "gzip": 1167, + "brotli": 1040 + }, + { + "path": "__tests__/__generated__/TestMutationInline_user_graphql.bs.js", + "minified": 698, + "gzip": 434, + "brotli": 376 + }, + { + "path": "__tests__/__generated__/TestMutationProvidedVariable_user_graphql.bs.js", + "minified": 898, + "gzip": 514, + "brotli": 443 + }, + { + "path": "__tests__/__generated__/TestMutationQuery_graphql.bs.js", + "minified": 3201, + "gzip": 1208, + "brotli": 1066 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.bs.js", + "minified": 2404, + "gzip": 990, + "brotli": 882 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.bs.js", + "minified": 2994, + "gzip": 1025, + "brotli": 923 + }, + { + "path": "__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 2929, + "gzip": 1004, + "brotli": 900 + }, + { + "path": "__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 3910, + "gzip": 1231, + "brotli": 1116 + }, + { + "path": "__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.bs.js", + "minified": 2788, + "gzip": 967, + "brotli": 880 + }, + { + "path": "__tests__/__generated__/TestMutation_user_graphql.bs.js", + "minified": 1757, + "gzip": 732, + "brotli": 645 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.bs.js", + "minified": 3137, + "gzip": 1238, + "brotli": 1103 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceQuery_graphql.bs.js", + "minified": 3720, + "gzip": 1318, + "brotli": 1193 + }, + { + "path": "__tests__/__generated__/TestNodeInterface_user_graphql.bs.js", + "minified": 720, + "gzip": 454, + "brotli": 387 + }, + { + "path": "__tests__/__generated__/TestNonReactQuery_graphql.bs.js", + "minified": 2468, + "gzip": 1077, + "brotli": 944 + }, + { + "path": "__tests__/__generated__/TestNonReact_user_graphql.bs.js", + "minified": 914, + "gzip": 519, + "brotli": 447 + }, + { + "path": "__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2798, + "gzip": 1170, + "brotli": 1035 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesMutation_graphql.bs.js", + "minified": 2713, + "gzip": 1016, + "brotli": 908 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesQuery_graphql.bs.js", + "minified": 2141, + "gzip": 948, + "brotli": 834 + }, + { + "path": "__tests__/__generated__/TestObserverQuery_graphql.bs.js", + "minified": 1893, + "gzip": 922, + "brotli": 813 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeQuery_graphql.bs.js", + "minified": 4371, + "gzip": 1458, + "brotli": 1305 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.bs.js", + "minified": 4990, + "gzip": 1625, + "brotli": 1474 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_query_graphql.bs.js", + "minified": 2756, + "gzip": 1055, + "brotli": 940 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_user_graphql.bs.js", + "minified": 1062, + "gzip": 549, + "brotli": 475 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionQuery_graphql.bs.js", + "minified": 4940, + "gzip": 1564, + "brotli": 1406 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.bs.js", + "minified": 5625, + "gzip": 1722, + "brotli": 1554 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_query_graphql.bs.js", + "minified": 3741, + "gzip": 1239, + "brotli": 1113 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_user_graphql.bs.js", + "minified": 993, + "gzip": 541, + "brotli": 471 + }, + { + "path": "__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.bs.js", + "minified": 2722, + "gzip": 1112, + "brotli": 991 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.bs.js", + "minified": 3657, + "gzip": 1295, + "brotli": 1149 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.bs.js", + "minified": 4215, + "gzip": 1439, + "brotli": 1293 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.bs.js", + "minified": 1106, + "gzip": 555, + "brotli": 486 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user_graphql.bs.js", + "minified": 2208, + "gzip": 879, + "brotli": 776 + }, + { + "path": "__tests__/__generated__/TestProvidedVariablesQuery_graphql.bs.js", + "minified": 5647, + "gzip": 1538, + "brotli": 1388 + }, + { + "path": "__tests__/__generated__/TestProvidedVariables_user_graphql.bs.js", + "minified": 1581, + "gzip": 572, + "brotli": 504 + }, + { + "path": "__tests__/__generated__/TestQueryInputObjectsQuery_graphql.bs.js", + "minified": 2061, + "gzip": 1018, + "brotli": 892 + }, + { + "path": "__tests__/__generated__/TestQuery_graphql.bs.js", + "minified": 2613, + "gzip": 1106, + "brotli": 978 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeQuery_graphql.bs.js", + "minified": 3713, + "gzip": 1409, + "brotli": 1274 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.bs.js", + "minified": 3822, + "gzip": 1412, + "brotli": 1264 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNode_user_graphql.bs.js", + "minified": 1705, + "gzip": 769, + "brotli": 668 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.bs.js", + "minified": 2193, + "gzip": 1016, + "brotli": 902 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgs_query_graphql.bs.js", + "minified": 988, + "gzip": 558, + "brotli": 485 + }, + { + "path": "__tests__/__generated__/TestRefetchingQuery_graphql.bs.js", + "minified": 3719, + "gzip": 1387, + "brotli": 1234 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.bs.js", + "minified": 2235, + "gzip": 1022, + "brotli": 905 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.bs.js", + "minified": 1000, + "gzip": 561, + "brotli": 489 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordQuery_graphql.bs.js", + "minified": 3761, + "gzip": 1393, + "brotli": 1240 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.bs.js", + "minified": 4514, + "gzip": 1581, + "brotli": 1426 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecord_user_graphql.bs.js", + "minified": 2080, + "gzip": 827, + "brotli": 721 + }, + { + "path": "__tests__/__generated__/TestRefetchingRefetchQuery_graphql.bs.js", + "minified": 4472, + "gzip": 1574, + "brotli": 1420 + }, + { + "path": "__tests__/__generated__/TestRefetching_user_graphql.bs.js", + "minified": 2068, + "gzip": 823, + "brotli": 721 + }, + { + "path": "__tests__/__generated__/TestRelayResolversAllQuery_graphql.bs.js", + "minified": 5361, + "gzip": 1536, + "brotli": 1386 + }, + { + "path": "__tests__/__generated__/TestRelayResolversQuery_graphql.bs.js", + "minified": 3046, + "gzip": 1181, + "brotli": 1052 + }, + { + "path": "__tests__/__generated__/TestRelayResolvers_user_graphql.bs.js", + "minified": 1300, + "gzip": 625, + "brotli": 542 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver2_graphql.bs.js", + "minified": 794, + "gzip": 465, + "brotli": 395 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver_graphql.bs.js", + "minified": 793, + "gzip": 463, + "brotli": 395 + }, + { + "path": "__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.bs.js", + "minified": 2191, + "gzip": 967, + "brotli": 855 + }, + { + "path": "__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.bs.js", + "minified": 1796, + "gzip": 841, + "brotli": 735 + }, + { + "path": "__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.bs.js", + "minified": 1829, + "gzip": 827, + "brotli": 719 + }, + { + "path": "__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.bs.js", + "minified": 902, + "gzip": 515, + "brotli": 443 + }, + { + "path": "__tests__/__generated__/TestSubscriptionQuery_graphql.bs.js", + "minified": 2542, + "gzip": 1073, + "brotli": 942 + }, + { + "path": "__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.bs.js", + "minified": 2552, + "gzip": 952, + "brotli": 837 + }, + { + "path": "__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.bs.js", + "minified": 3038, + "gzip": 1066, + "brotli": 953 + }, + { + "path": "__tests__/__generated__/TestSubscription_user_graphql.bs.js", + "minified": 1061, + "gzip": 535, + "brotli": 455 + }, + { + "path": "__tests__/__generated__/TestTestingHelpersQuery_graphql.bs.js", + "minified": 3448, + "gzip": 1298, + "brotli": 1170 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_plural_user_graphql.bs.js", + "minified": 1002, + "gzip": 538, + "brotli": 466 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_sub_user_graphql.bs.js", + "minified": 724, + "gzip": 458, + "brotli": 390 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_user_graphql.bs.js", + "minified": 1180, + "gzip": 607, + "brotli": 521 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentQuery_graphql.bs.js", + "minified": 3556, + "gzip": 1264, + "brotli": 1124 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentUser_user_graphql.bs.js", + "minified": 923, + "gzip": 520, + "brotli": 448 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_member_graphql.bs.js", + "minified": 1547, + "gzip": 696, + "brotli": 609 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_plural_member_graphql.bs.js", + "minified": 1561, + "gzip": 707, + "brotli": 634 + }, + { + "path": "__tests__/__generated__/TestUnionsQuery_graphql.bs.js", + "minified": 5037, + "gzip": 1522, + "brotli": 1380 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.bs.js", + "minified": 2816, + "gzip": 1121, + "brotli": 997 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_query_graphql.bs.js", + "minified": 1248, + "gzip": 607, + "brotli": 517 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_updatableUser_graphql.bs.js", + "minified": 678, + "gzip": 363, + "brotli": 321 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.bs.js", + "minified": 1298, + "gzip": 610, + "brotli": 529 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_graphql.bs.js", + "minified": 2607, + "gzip": 1046, + "brotli": 936 + }, + { + "path": "__tests__/__generated__/UserAvatar_user_graphql.bs.js", + "minified": 1049, + "gzip": 572, + "brotli": 494 + }, + { + "path": "__tests__/__generated__/UserMeta____relay_model_instance_graphql.bs.js", + "minified": 785, + "gzip": 476, + "brotli": 404 + }, + { + "path": "__tests__/__generated__/UserMeta_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/UserName_user_graphql.bs.js", + "minified": 785, + "gzip": 458, + "brotli": 393 + }, + { + "path": "__tests__/__generated__/User_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.bs.js", + "minified": 1418, + "gzip": 570, + "brotli": 499 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.bs.js", + "minified": 5051, + "gzip": 1484, + "brotli": 1332 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.bs.js", + "minified": 2236, + "gzip": 845, + "brotli": 759 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/size-budgets.json b/packages/rescript-relay/benchmarks/size-budgets.json index 493dc776..cda6d1ca 100644 --- a/packages/rescript-relay/benchmarks/size-budgets.json +++ b/packages/rescript-relay/benchmarks/size-budgets.json @@ -1,12 +1,12 @@ { "combined": { - "minified": 277148, - "gzip": 37034, - "brotli": 26760 + "minified": 275365, + "gzip": 36682, + "brotli": 26495 }, "separate": { - "minified": 307258, - "gzip": 120164, - "brotli": 106574 + "minified": 305561, + "gzip": 119565, + "brotli": 106023 } } diff --git a/packages/rescript-relay/docs/conversion-contract.md b/packages/rescript-relay/docs/conversion-contract.md index 4da19fcf..aef96f78 100644 --- a/packages/rescript-relay/docs/conversion-contract.md +++ b/packages/rescript-relay/docs/conversion-contract.md @@ -126,3 +126,9 @@ local to a conversion's callback table, assigned deterministically across scalar and union callbacks, and do not change response traversal. Public preparation still accepts named callback keys. Plans may be shared, but callback bindings are always prepared against their own table and snapshotted independently. + +The compiler may omit list-depth hints when no special conversion operation +exists at or below that path. Generic nullable traversal handles those plain +lists. List wrappers around scalars, unions, references, opaque values, and +fragment-bearing records are retained. An entirely empty plan uses the shared +converter; named input references are never removed by this optimization. From 66f95a1e276d9090aa19abb7bc2e5428429d92ce Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 11:22:21 +0200 Subject: [PATCH 10/23] Prototype ReScript conversion runtime behind isolated benchmark harness --- .../benchmarks/rescript-runtime/.gitignore | 5 + .../benchmarks/rescript-runtime/README.md | 34 ++ .../benchmarks/rescript-runtime/build.js | 26 ++ .../benchmarks/rescript-runtime/entry.mjs | 5 + .../benchmarks/rescript-runtime/rescript.json | 6 + .../benchmarks/rescript-runtime/resolver.js | 7 + .../src/RescriptRelay_Conversion.res | 314 ++++++++++++++++++ .../src/RescriptRelay_ConversionInterop.res | 109 ++++++ .../src/RescriptRelay_LegacyConversion.res | 261 +++++++++++++++ .../benchmarks/rescript-runtime/test.js | 31 ++ 10 files changed, 798 insertions(+) create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/.gitignore create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/README.md create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/build.js create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/entry.mjs create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/rescript.json create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/resolver.js create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_LegacyConversion.res create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/test.js diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/.gitignore b/packages/rescript-relay/benchmarks/rescript-runtime/.gitignore new file mode 100644 index 00000000..f0656617 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/.gitignore @@ -0,0 +1,5 @@ +lib/ +.rescript* +.bsb.lock +src/*.mjs +output/ diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/README.md b/packages/rescript-relay/benchmarks/rescript-runtime/README.md new file mode 100644 index 00000000..942c6476 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/README.md @@ -0,0 +1,34 @@ +# ReScript runtime experiment + +This ports both the prepared converter and the legacy traversal without changing +the shipping runtime. Performance is an adoption requirement, not an assumption. +The experiment is excluded from the package's ReScript sources and release build. + +The conversion and preparation logic lives in `src/*.res`. Dynamic property +access is isolated in `RescriptRelay_ConversionInterop.res`. Three small raw-JS +object loops preserve allocation-free `for...in` traversal, property order, +metadata handling and lazy copying. ReScript's `Object.keys` alternative allocates +an array for each visited object; the initial direct port was slower. This is +therefore a hybrid port, not an entirely ReScript implementation. + +From `packages/rescript-relay`: + +```sh +node benchmarks/rescript-runtime/build.js +node benchmarks/rescript-runtime/test.js +ENABLE_PERSISTING=true node benchmarks/rescript-runtime/test.js +node benchmarks/conversion.js --prepared --implementation benchmarks/rescript-runtime/output/utils.cjs +node benchmarks/conversion.js --implementation benchmarks/rescript-runtime/output/utils.cjs +``` + +Build with the repository's pinned ReScript and esbuild versions. The standalone +build bundles ESM and derives an equivalent CommonJS export boundary. It does not +add module wrappers or ReScript runtime dependencies to the measured candidate. +Tests resolve the actual shipping `src/utils.js` path to the candidate, including +imports made by compiled ReScript bindings. Native ESM/CommonJS parity is checked +separately. Existing tests remain unchanged. + +Preliminary results: all 242 main tests pass; inlining legacy instruction lookups +removed most of its initial regression. Prepared object-heavy cases improved, +but opaque lists remained slower. Further measurements and the adoption decision +will be recorded here. Do not use this prototype as a shipping replacement. diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/build.js b/packages/rescript-relay/benchmarks/rescript-runtime/build.js new file mode 100644 index 00000000..adf73985 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/build.js @@ -0,0 +1,26 @@ +#!/usr/bin/env node +// Standalone experiment: never replaces the shipping runtime or release build. +const fs = require("fs"); +const path = require("path"); +const { spawn } = require("child_process"); +const esbuild = require("esbuild"); +async function build() { + const compiler = path.resolve(__dirname, "../../node_modules/.bin/rescript"); + await new Promise((resolve, reject) => { + const child = spawn(compiler, ["build"], {cwd: __dirname, stdio: "inherit"}); + child.on("error", reject); + child.on("exit", code => code === 0 ? resolve() : reject(new Error(`ReScript exited ${code}`))); + }); + const output = path.join(__dirname, "output"); + await esbuild.build({ + entryPoints: [path.join(__dirname, "entry.mjs")], + bundle: true, + format: "esm", + outfile: path.join(output, "utils.mjs"), + }); + const source = fs.readFileSync(path.join(output, "utils.mjs"), "utf8"); + const boundary = /export \{([\w\s,]+)\};\s*$/; + if (!boundary.test(source)) throw new Error("Unexpected ESM export boundary"); + fs.writeFileSync(path.join(output, "utils.cjs"), source.replace(boundary, "module.exports = {$1};\n")); +} +build().catch(error => {console.error(error); process.exitCode = 1;}); diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/entry.mjs b/packages/rescript-relay/benchmarks/rescript-runtime/entry.mjs new file mode 100644 index 00000000..96248862 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/entry.mjs @@ -0,0 +1,5 @@ +export {prepareConversion, convertWithoutPlan} from './src/RescriptRelay_Conversion.mjs'; +export {traverser} from './src/RescriptRelay_LegacyConversion.mjs'; +export function runConversion(convert, value) { + return convert(value); +} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/rescript.json b/packages/rescript-relay/benchmarks/rescript-runtime/rescript.json new file mode 100644 index 00000000..3fc3b7df --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/rescript.json @@ -0,0 +1,6 @@ +{ + "name": "relay-conversion-runtime-experiment", + "sources": ["src"], + "package-specs": {"module": "esmodule", "in-source": true}, + "suffix": ".mjs" +} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/resolver.js b/packages/rescript-relay/benchmarks/rescript-runtime/resolver.js new file mode 100644 index 00000000..badabc36 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/resolver.js @@ -0,0 +1,7 @@ +const path = require("path"); +const runtime = path.resolve(__dirname, "../../src/utils.js"); +const candidate = path.resolve(__dirname, "output/utils.cjs"); +module.exports = (request, options) => { + const resolved = options.defaultResolver(request, options); + return resolved === runtime ? candidate : resolved; +}; diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res new file mode 100644 index 00000000..3371d72c --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res @@ -0,0 +1,314 @@ +open RescriptRelay_ConversionInterop + +type rec node = {children: dict, instructions: dict} + +%%private( + let isOption = value => (get(value, "BS_PRIVATE_NESTED_SOME_NONE"): float) >= 0.0 + let isMetadata = key => + key->startsWith("__") && + key !== "__typename" && + key !== "__id" && + !(key->startsWith("__relay_internal")) + let makeNode = () => {children: create(), instructions: create()} + let readPlan = plan => { + let rawRoots: value = if truthy(plan) { + get(plan, "roots") + } else { + jsUndefined + } + if ( + !truthy(plan) || + get(plan, "version") !== cast(2) || + !truthy(rawRoots) || + typeOf(rawRoots) !== "object" + ) { + fail("Invalid conversion plan: expected version 2 and roots") + } + let roots = create() + let fields1 = keys(rawRoots) + for index1 in 0 to Array.length(fields1) - 1 { + let name = unsafeAt(fields1, index1) + let entries: value = get(rawRoots, name) + if !isArray(entries) { + fail("Invalid conversion root: " ++ name) + } + let root = makeNode() + set(roots, name, root) + for i in 0 to length(entries) - 1 { + let entry = at(entries, i) + let path: value = if truthy(entry) { + get(entry, "path") + } else { + jsUndefined + } + if !isArray(path) { + fail("Invalid conversion path in " ++ name) + } + let target = ref(root) + for j in 0 to length(path) - 1 { + let rawKey = at(path, j) + if typeOf(rawKey) !== "string" { + fail("Invalid conversion path in " ++ name) + } + let key: string = cast(rawKey) + if hasOwn(target.contents.children, key) { + target := get(target.contents.children, key) + } else { + let child = makeNode() + set(target.contents.children, key, child) + target := child + } + } + let fields2 = keys(entry) + for index2 in 0 to Array.length(fields2) - 1 { + let key = unsafeAt(fields2, index2) + switch key { + | "path" => () + | "list" | "scalar" | "union" | "reference" | "opaque" | "fragments" => + let value: value = get(entry, key) + if ( + hasOwn(target.contents.instructions, key) && + get(target.contents.instructions, key) !== value + ) { + fail("Conflicting conversion instruction: " ++ key) + } + set(target.contents.instructions, key, value) + | _ => fail("Unknown conversion instruction: " ++ key) + } + } + } + } + roots + } + let arrayOf = (convert: converter): converter => + values => { + let result = ref(jsUndefined) + for i in 0 to length(values) - 1 { + if hasIndex(i, values) { + let value = at(values, i) + let next = convert(value) + if next !== value { + if result.contents === jsUndefined { + result := slice(values) + } + put(result.contents, i, next) + } + } + } + if result.contents === jsUndefined { + values + } else { + result.contents + } + } +) + +let prepareConversion = ( + plan: value, + callbacks: value, + nullable: value, + rawRootName: value, +): converter => { + if nullable !== jsUndefined && nullable !== jsNull { + fail("Invalid conversion nullable sentinel") + } + let rootName: string = if rawRootName === jsUndefined { + "__root" + } else { + cast(rawRootName) + } + let roots = readPlan(plan) + if !hasOwn(roots, rootName) { + fail("Missing conversion root: " ++ rootName) + } + let converters: dict = create() + let nullableOnly: converter = value => + if isNullable(value) { + nullable + } else { + value + } + let optional = (convert: converter) => { + if convert === nullableOnly { + nullableOnly + } else { + value => + if isNullable(value) { + nullable + } else if isOption(value) { + value + } else { + convert(value) + } + } + } + let rec any: converter = value => { + if isNullable(value) { + nullable + } else if typeOf(value) !== "object" || isOption(value) { + value + } else if isArray(value) { + anyArray(value) + } else { + plainRecord(value, any, isMetadata) + } + } + and anyArray: converter = values => { + let result = ref(jsUndefined) + for i in 0 to length(values) - 1 { + if hasIndex(i, values) { + let value = at(values, i) + let next = any(value) + if next !== value { + if result.contents === jsUndefined { + result := slice(values) + } + put(result.contents, i, next) + } + } + } + if result.contents === jsUndefined { + values + } else { + result.contents + } + } + let callback = name => { + if ( + !truthy(callbacks) || !hasOwn(callbacks, name) || typeOf(get(callbacks, name)) !== "function" + ) { + fail("Missing conversion callback: " ++ name) + } + (get(callbacks, name): converter) + } + let rec compile = node => { + let ops = node.instructions + let operations = ["scalar", "union", "reference"]->Array.filter(key => hasOwn(ops, key)) + let allOperations = if hasOwn(ops, "opaque") { + Array.concat(operations, ["opaque"]) + } else { + operations + } + if Array.length(allOperations) > 1 { + fail("Conflicting conversion operations: " ++ Array.join(allOperations, ", ")) + } + let fields4 = operations + for index4 in 0 to Array.length(fields4) - 1 { + let key = unsafeAt(fields4, index4) + if typeOf(get(ops, key)) !== "string" { + fail("Invalid conversion " ++ key) + } + } + let fields5 = ["opaque", "fragments"] + for index5 in 0 to Array.length(fields5) - 1 { + let key = unsafeAt(fields5, index5) + if hasOwn(ops, key) && get(ops, key) !== cast(true) { + fail("Invalid conversion " ++ key) + } + } + let rawDepth: value = get(ops, "list") + let depth: int = if rawDepth === jsUndefined { + 0 + } else { + cast(rawDepth) + } + if !isSafeInteger(cast(depth)) || depth < 0 { + fail("Invalid conversion list depth") + } + let names = keys(node.children) + let scalar: value = get(ops, "scalar") + let reference: value = get(ops, "reference") + let opaque = get(ops, "opaque") === cast(true) + let fragments = get(ops, "fragments") === cast(true) + let base = if scalar !== jsUndefined || opaque || reference !== jsUndefined { + if Array.length(names) > 0 || fragments { + fail("Leaf conversion cannot have child fields or fragments") + } + if scalar !== jsUndefined { + callback(cast(scalar)) + } else if opaque { + nullableOnly + } else { + let target: string = cast(reference) + if !hasOwn(roots, target) { + fail("Missing conversion reference: " ++ target) + } + value => + (get(converters, target): converter)( + if hasOwn(value, "__$inputUnion") { + unwrapInputUnion(value) + } else { + value + }, + ) + } + } else { + let children: dict = create() + let fields6 = names + for index6 in 0 to Array.length(fields6) - 1 { + let name = unsafeAt(fields6, index6) + set(children, name, compile(get(node.children, name))) + } + let union: value = get(ops, "union") + if union !== jsUndefined { + if fragments { + fail("Union fragments belong on member plans") + } + let union = callback(cast(union)) + let member = value => { + let convert: converter = get(children, get(value, "__typename")) + if cast(convert) === jsUndefined { + any + } else { + convert + } + } + if nullable === jsNull { + value => member(value)(union(value)) + } else { + value => union(member(value)(value)) + } + } else if Array.length(names) === 0 && !fragments { + any + } else { + makeRecord(children, fragments, any, isMetadata) + } + } + let convert = ref(optional(base)) + for _i in 1 to depth { + convert := optional(arrayOf(convert.contents)) + } + convert.contents + } + let fields7 = keys(roots) + for index7 in 0 to Array.length(fields7) - 1 { + let name = unsafeAt(fields7, index7) + set(converters, name, compile(get(roots, name))) + } + let convert: converter = get(converters, rootName) + let plural = arrayOf(convert) + let root: node = get(roots, rootName) + let allowPlural = + get(root.instructions, "list") === jsUndefined && + get(root.instructions, "scalar") === jsUndefined && + get(root.instructions, "reference") === jsUndefined && + get(root.instructions, "opaque") !== cast(true) + value => + if isArray(value) && allowPlural { + plural(value) + } else { + convert(value) + } +} + +%%private( + let emptyPlan: value = %raw(json`{"version":2,"roots":{"__root":[]}}`) + let readWithoutPlan = prepareConversion(emptyPlan, jsUndefined, jsUndefined, jsUndefined) + let writeWithoutPlan = prepareConversion(emptyPlan, jsUndefined, jsNull, jsUndefined) +) +let convertWithoutPlan = (value, nullable) => + if nullable === jsNull { + writeWithoutPlan(value) + } else { + readWithoutPlan(value) + } diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res new file mode 100644 index 00000000..0518bc80 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res @@ -0,0 +1,109 @@ +// Dynamic Relay values include jsNull, jsUndefined, custom scalar instances and +// ReScript option markers. Keep unchecked property access at this FFI boundary. +type value +type converter = value => value +external jsUndefined: value = "%undefined" +external jsNull: value = "%null" +external cast: 'a => 'b = "%identity" +external isNullable: value => bool = "%is_nullable" +external typeOf: 'a => string = "%typeof" +@get_index external get: ('object, string) => 'value = "" +@set_index external set: ('object, string, 'value) => unit = "" +@get_index external unsafeAt: (array<'a>, int) => 'a = "" +@get_index external at: (value, int) => value = "" +@set_index external put: (value, int, value) => unit = "" +@get external length: 'a => int = "length" +@send external slice: value => value = "slice" +@send external startsWith: (string, string) => bool = "startsWith" +@val external isArray: 'a => bool = "Array.isArray" +@val external keys: 'a => array = "Object.keys" +@val external create: (@as(json`null`) _, unit) => dict<'a> = "Object.create" +@val external isSafeInteger: value => bool = "Number.isSafeInteger" +@val external truthy: 'a => bool = "Boolean" +let hasOwn: ( + 'object, + string, +) => bool = %raw(`(object, key) => Object.prototype.hasOwnProperty.call(object, key)`) +let hasIndex: (int, value) => bool = %raw(`(index, value) => index in value`) +let unwrapInputUnion: value => value = %raw(`value => ({[value.__$inputUnion]: value._0})`) +let fail: string => 'a = %raw(`message => {throw new Error(message);}`) +// ReScript has no allocation-free `for ... in` construct. These two kernels +// preserve own-key order and lazy copying without allocating a keys array. +let plainRecord: ( + value, + converter, + string => bool, +) => value = %raw(`(value, convert, isMetadata) => { + let result; + for (const key in value) { + if (!Object.prototype.hasOwnProperty.call(value,key) || isMetadata(key)) continue; + const original = value[key]; + const next = convert(original); + if (next !== original) { + if (result === undefined) result = {...value}; + result[key] = next; + } + } + return result === undefined ? value : result; +}`) +let makeRecord: ( + dict, + bool, + converter, + string => bool, +) => converter = %raw(`(fields, fragments, any, isMetadata) => value => { + let result; + if (fragments) { + const refs = {...value}; + result = {...value, fragmentRefs: refs, updatableFragmentRefs: refs}; + } + for (const key in value) { + if (!Object.prototype.hasOwnProperty.call(value,key) || isMetadata(key)) continue; + const original = value[key]; + const convert = fields[key]; + const next = convert === undefined ? any(original) : convert(original); + if (next !== original) { + if (result === undefined) result = {...value}; + result[key] = next; + } + } + return result === undefined ? value : result; +}`) +let withLegacyFragments: value => value = %raw(`value => {const result = Object.assign({},value); result.fragmentRefs = Object.assign({},value); result.updatableFragmentRefs = result.fragmentRefs; return result;}`) +let hasProperty: (string, value) => bool = %raw(`(key, value) => key in value`) +@send external map: (value, (value, int, value) => value) => value = "map" +let legacyRecord: ( + value, + string, + value, + value, + value, + value, + bool, + (value, value, value, string, value, value, value) => value, +) => value = %raw(`(maps, prefix, obj, instructions, converters, nullable, fragment, convertField) => { + let result; + if (fragment) { + result = Object.assign({},obj); + result.fragmentRefs = Object.assign({},obj); + result.updatableFragmentRefs = result.fragmentRefs; + } + for (const key in obj) { + if (key.startsWith('__') && key !== '__typename' && key !== '__id' && !key.startsWith('__relay_internal')) continue; + const value = obj[key]; + let converted; + if (value == null) converted = nullable; + else if (value.BS_PRIVATE_NESTED_SOME_NONE >= 0) continue; + else { + const path = prefix + key; + let instruction = instructions[path]; + if (instruction === undefined && typeof value !== 'object') continue; + converted = convertField(value, instruction, maps, path, instructions, converters, nullable); + } + if (converted !== value) { + if (result === undefined) result = Object.assign({},obj); + result[key] = converted; + } + } + return result === undefined ? obj : result; +}`) diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_LegacyConversion.res b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_LegacyConversion.res new file mode 100644 index 00000000..93deffe1 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_LegacyConversion.res @@ -0,0 +1,261 @@ +open RescriptRelay_ConversionInterop + +%%private( + let empty: value = %raw(`Object.freeze({})`) + let fallback = value => + if truthy(value) { + value + } else { + empty + } + let unwrap = value => + if !isNullable(value) && typeOf(value) === "object" && hasProperty("__$inputUnion", value) { + unwrapInputUnion(value) + } else { + value + } +) + +let rec traverser = ( + root: value, + instructionMaps: value, + callbacks: value, + nullable: value, + rootObjectKey: value, +): value => { + if !truthy(root) { + nullable + } else { + let maps = if truthy(instructionMaps) { + instructionMaps + } else { + empty + } + let key: string = if truthy(rootObjectKey) { + cast(rootObjectKey) + } else { + "__root" + } + let instructions = fallback(get(maps, key)) + let callbacks = if truthy(callbacks) { + callbacks + } else { + empty + } + let rootInstruction = fallback(get(instructions, "")) + let union: value = get(callbacks, get(rootInstruction, "u")) + let fragment = get(rootInstruction, "f") === cast("") + let convertRoot = value => { + if isNullable(value) { + nullable + } else { + let prefix = if !isNullable(union) { + (get(value, "__typename"): string) ++ "_" + } else { + "" + } + let hasFragment = if !isNullable(union) { + get(fallback(get(instructions, get(value, "__typename"))), "f") === cast("") + } else { + fragment + } + let result = legacyRecord( + maps, + prefix, + value, + instructions, + callbacks, + nullable, + hasFragment, + convertField, + ) + if !isNullable(union) { + (cast(union): converter)(result) + } else { + result + } + } + } + if isArray(root) { + let result = ref(jsUndefined) + let i = ref(0) + while i.contents < length(root) { + let index = i.contents + if hasIndex(index, root) { + let original = at(root, index) + let next = convertRoot(original) + if next !== original { + if result.contents === jsUndefined { + result := slice(root) + } + put(result.contents, index, next) + } + } + i := i.contents + 1 + } + if result.contents === jsUndefined { + root + } else { + result.contents + } + } else { + convertRoot(root) + } + } +} +and convertUnion = (value, convert: converter, maps, path, instructions, callbacks, nullable) => { + let unionPath = path ++ "_" ++ (get(value, "__typename"): string) + let fragment = get(fallback(get(instructions, unionPath)), "f") === cast("") + let raw = if nullable === jsNull { + convert(value) + } else { + value + } + let result = legacyRecord( + maps, + unionPath ++ "_", + raw, + instructions, + callbacks, + nullable, + fragment, + convertField, + ) + if nullable === jsUndefined { + convert(result) + } else { + result + } +} +and convertField = (value, rawInstruction, maps, path, instructions, callbacks, nullable) => { + let instruction = if truthy(rawInstruction) { + rawInstruction + } else { + empty + } + let array = isArray(value) + let customArray = if typeOf(get(instruction, "ca")) === "string" { + get(callbacks, get(instruction, "ca")) + } else { + jsUndefined + } + if array && truthy(customArray) { + map(value, (item, index, array) => { + if isNullable(item) { + nullable + } else if (get(item, "BS_PRIVATE_NESTED_SOME_NONE"): float) >= 0.0 { + item + } else { + (cast(customArray): (value, int, value) => value)(item, index, array) + } + }) + } else { + let blocked = typeOf(get(instruction, "b")) === "string" + if blocked && get(instruction, "b") !== cast("a") { + value + } else { + let custom = if typeOf(get(instruction, "c")) === "string" { + get(callbacks, get(instruction, "c")) + } else { + jsUndefined + } + if array && truthy(custom) { + (cast(custom): converter)(value) + } else { + let root = if typeOf(get(instruction, "r")) === "string" { + get(maps, get(instruction, "r")) + } else { + jsUndefined + } + let enumConverter = if typeOf(get(instruction, "e")) === "string" { + get(callbacks, get(instruction, "e")) + } else { + jsUndefined + } + let union = if typeOf(get(instruction, "u")) === "string" { + get(callbacks, get(instruction, "u")) + } else { + jsUndefined + } + let fragment = get(instruction, "f") === cast("") + if array { + let result = ref(jsUndefined) + let i = ref(0) + while i.contents < length(value) { + let index = i.contents + if hasIndex(index, value) { + let item = at(value, index) + let next = if isNullable(item) { + nullable + } else if truthy(root) { + traverser(unwrap(item), maps, callbacks, nullable, get(instruction, "r")) + } else if truthy(enumConverter) { + (cast(enumConverter): converter)(item) + } else if ( + truthy(union) && typeOf(item) === "object" && !isNullable(get(item, "__typename")) + ) { + convertUnion(item, cast(union), maps, path, instructions, callbacks, nullable) + } else if typeOf(item) === "object" && !isArray(item) { + if blocked { + if fragment { + withLegacyFragments(item) + } else { + item + } + } else { + legacyRecord( + maps, + path ++ "_", + item, + instructions, + callbacks, + nullable, + fragment, + convertField, + ) + } + } else { + item + } + if next !== item { + if result.contents === jsUndefined { + result := slice(value) + } + put(result.contents, index, next) + } + } + i := i.contents + 1 + } + if result.contents === jsUndefined { + value + } else { + result.contents + } + } else if truthy(root) { + traverser(unwrap(value), maps, callbacks, nullable, get(instruction, "r")) + } else if truthy(custom) { + (cast(custom): converter)(value) + } else if truthy(enumConverter) { + (cast(enumConverter): converter)(value) + } else if typeOf(value) === "object" { + if truthy(union) && !isNullable(get(value, "__typename")) { + convertUnion(value, cast(union), maps, path, instructions, callbacks, nullable) + } else { + legacyRecord( + maps, + path ++ "_", + value, + instructions, + callbacks, + nullable, + fragment, + convertField, + ) + } + } else { + value + } + } + } + } +} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/test.js b/packages/rescript-relay/benchmarks/rescript-runtime/test.js new file mode 100644 index 00000000..4d0e3cc8 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/test.js @@ -0,0 +1,31 @@ +#!/usr/bin/env node +const assert = require("assert/strict"); +const path = require("path"); +const {pathToFileURL} = require("url"); +const {spawn} = require("child_process"); +async function test() { + const candidate = require("./output/utils.cjs"); + const esm = await import(pathToFileURL(path.join(__dirname, "output/utils.mjs"))); + assert.deepEqual(Object.keys(candidate).sort(), Object.keys(esm).sort()); + const {cases, converters} = require("../fixtures"); + for (const fixture of cases) { + for (const nullable of [null, undefined]) { + const convert = runtime => runtime.runConversion(runtime.prepareConversion(fixture.plan, converters, nullable), fixture.root); + assert.deepEqual(convert(esm), convert(candidate), fixture.name); + assert.deepEqual(esm.traverser(fixture.root, fixture.maps, converters, nullable), candidate.traverser(fixture.root, fixture.maps, converters, nullable), fixture.name); + assert.deepEqual(esm.convertWithoutPlan(fixture.root, nullable), candidate.convertWithoutPlan(fixture.root, nullable), fixture.name); + } + } + const config = { + ...require("../../jest.config"), + rootDir: path.resolve(__dirname, "../.."), + bail: false, + resolver: path.join(__dirname, "resolver.js"), + }; + await new Promise((resolve, reject) => { + const child = spawn(process.execPath, [require.resolve("jest/bin/jest"), "--config", JSON.stringify(config), "--runInBand"], {stdio: "inherit"}); + child.on("error", reject); + child.on("exit", code => code === 0 ? resolve() : reject(new Error(`Jest exited ${code}`))); + }); +} +test().catch(error => {console.error(error); process.exitCode = 1;}); From 3de062b8894c1bd7fea787dbe0ae369c0c5803e5 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 11:29:06 +0200 Subject: [PATCH 11/23] Record runtime port tradeoffs and retain faster shipping JavaScript --- packages/rescript-relay/benchmarks/README.md | 4 + .../benchmarks/rescript-runtime/README.md | 70 +- .../benchmarks/rescript-runtime/compare.js | 95 + .../results/paired-final.json | 2437 +++++++++++++++++ .../rescript-runtime/results/size.json | 26 + .../rescript-runtime/results/summary.json | 512 ++++ .../benchmarks/rescript-runtime/size.js | 23 + .../src/RescriptRelay_Conversion.res | 76 +- .../src/RescriptRelay_ConversionInterop.res | 2 +- 9 files changed, 3199 insertions(+), 46 deletions(-) create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/compare.js create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/results/paired-final.json create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/results/size.json create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/results/summary.json create mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/size.js diff --git a/packages/rescript-relay/benchmarks/README.md b/packages/rescript-relay/benchmarks/README.md index 4b2b2af5..12d0072f 100644 --- a/packages/rescript-relay/benchmarks/README.md +++ b/packages/rescript-relay/benchmarks/README.md @@ -82,3 +82,7 @@ cache or dependency changes were needed. See [bundle-size measurements and budgets](SIZE.md) for complete generated JS, shared/separate bundles, gzip/Brotli reports, and reproduction commands. + +See the [ReScript runtime experiment](rescript-runtime/README.md) for a tested +port of both converters, paired timing results, bundle measurements, and the +reason the shipping runtime remains JavaScript. diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/README.md b/packages/rescript-relay/benchmarks/rescript-runtime/README.md index 942c6476..8a4eb714 100644 --- a/packages/rescript-relay/benchmarks/rescript-runtime/README.md +++ b/packages/rescript-relay/benchmarks/rescript-runtime/README.md @@ -1,7 +1,8 @@ # ReScript runtime experiment -This ports both the prepared converter and the legacy traversal without changing -the shipping runtime. Performance is an adoption requirement, not an assumption. +Decision: retain the shipping JavaScript runtime. This prototype ports both the +prepared converter and the legacy traversal, but does not preserve performance +across the measured cases and increases runtime bundle size. The experiment is excluded from the package's ReScript sources and release build. The conversion and preparation logic lives in `src/*.res`. Dynamic property @@ -19,6 +20,8 @@ node benchmarks/rescript-runtime/test.js ENABLE_PERSISTING=true node benchmarks/rescript-runtime/test.js node benchmarks/conversion.js --prepared --implementation benchmarks/rescript-runtime/output/utils.cjs node benchmarks/conversion.js --implementation benchmarks/rescript-runtime/output/utils.cjs +node benchmarks/rescript-runtime/compare.js benchmarks/rescript-runtime/output/comparison.json +node benchmarks/rescript-runtime/size.js ``` Build with the repository's pinned ReScript and esbuild versions. The standalone @@ -28,7 +31,62 @@ Tests resolve the actual shipping `src/utils.js` path to the candidate, includin imports made by compiled ReScript bindings. Native ESM/CommonJS parity is checked separately. Existing tests remain unchanged. -Preliminary results: all 242 main tests pass; inlining legacy instruction lookups -removed most of its initial regression. Prepared object-heavy cases improved, -but opaque lists remained slower. Further measurements and the adoption decision -will be recorded here. Do not use this prototype as a shipping replacement. +## Results and decision (2026-09-22) + +All **243 existing tests pass** against the candidate: 242 main tests in 49 suites, +including the 139 utility tests and mounted Relay integration tests, plus the +separate persisted-query test. Native ESM/CommonJS exports also agree on all +benchmark fixtures in both directions. This establishes useful compatibility +evidence; it is not exhaustive correctness, a new coverage claim, or a completed +production rollout. + +Three runs used Node 24.16.0 on AMD RYZEN AI MAX+ 395, with 31 alternating +baseline/candidate pairs per case. Each pair reverses execution order; calibration +and preparation are outside warm timings. All comparisons use the same fixture +version and the JavaScript runtime from `b0f009a`. The shared host was busy, so +small differences and individual timings are noisy. These are conversion +microbenchmarks, not app latency measurements or cross-engine guarantees. + +The range below is the median paired **conversion-time change** in each run +(negative is faster): + +| Case | Prepared port | Legacy port | +| --- | ---: | ---: | +| Small fragment | -16.5% to -8.9% | -3.6% to +0.9% | +| Connection, 100 rows | -21.7% to -17.9% | -3.0% to +0.4% | +| Plural fragment, 100 rows | -19.4% to -12.1% | -7.2% to +4.3% | +| Union list, 100 rows | -22.2% to -18.0% | +0.8% to +5.2% | +| Custom scalar list | -1.8% to +2.2% | +2.5% to +9.6% | +| Opaque JSON list | **+14.0% to +20.0%** | +2.1% to +4.5% | +| Recursive inputs | -14.3% to -2.3% | -4.4% to +4.1% | + +All cases and source hashes are in [summary.json](results/summary.json); the final +run's individual measurements are in [paired-final.json](results/paired-final.json). +Earlier tuning removed most of the legacy port's initial regression by inlining +instruction lookups. Moving the prepared array converter into the preparation +scope did not resolve the opaque-list regression. + +The object-heavy gains do not establish that ReScript itself is faster. The +prototype also specializes generic record traversal to avoid looking up fields +in an empty instruction dictionary, and its compiled generic array traversal is +inlined. Those changes could be investigated independently in JavaScript. + +Equivalent complete ESM runtime bundles, retaining all four public exports and +minified with esbuild 0.25.12: + +| Bytes | JavaScript | Hybrid ReScript | Increase | +| --- | ---: | ---: | ---: | +| Minified | 5,578 | 6,328 | 750 | +| Gzip | 2,238 | 2,638 | **400 (+17.9%)** | +| Brotli | 2,032 | 2,352 | 320 | + +[Size details](results/size.json) also include equivalent CommonJS-entry bundles. +These numbers measure only the shared runtime; compiler-generated instructions +are unchanged. This experiment is not included in the release, so it adds no +production bundle bytes. + +The hybrid approach needs substantial dynamic FFI and handwritten JS object +loops, so it has not clearly simplified maintenance either. Keep the prototype +isolated and retain the already-tested, optimized JavaScript implementation. +Future adoption needs to resolve the regressions, weigh the size/maintenance cost, +and validate supported JS engines; passing the existing tests alone is not enough. diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/compare.js b/packages/rescript-relay/benchmarks/rescript-runtime/compare.js new file mode 100644 index 00000000..9a0a6e6a --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/compare.js @@ -0,0 +1,95 @@ +#!/usr/bin/env node +// Alternate order within each pair to reduce temporal bias. These are warm +// microbenchmarks, not end-to-end latency or proof of parity across JS engines. +const {performance} = require("perf_hooks"); +const fs = require("fs"); +const assert = require("assert/strict"); +const os = require("os"); +const crypto = require("crypto"); +const v8 = require("v8"); +const {cases, converters} = require("../fixtures"); +const baseline = require("../../src/utils"); +const candidate = require("./output/utils.cjs"); +const samples = 31; +const targetSampleMs = 20; +let sink; +function batch(convert, root, count) { + const start = performance.now(); + for (let i = 0; i < count; i++) sink = convert(root); + return (performance.now() - start) * 1e6 / count; +} +function median(values) { + return [...values].sort((a, b) => a - b)[Math.floor(values.length / 2)]; +} +function hash(filename) { + return crypto.createHash("sha256") + .update(fs.readFileSync(require.resolve(filename))).digest("hex"); +} +function build(runtime, fixture, mode) { + if (mode === "legacy") { + return value => runtime.traverser(value, fixture.maps, converters, fixture.nullable); + } + if (Object.keys(fixture.plan.roots).length === 1 && fixture.plan.roots.__root.length === 0) { + return value => runtime.convertWithoutPlan(value, fixture.nullable); + } + return runtime.prepareConversion(fixture.plan, converters, fixture.nullable); +} +if (!process.argv[2]) { + throw new Error("Usage: node benchmarks/rescript-runtime/compare.js "); +} +const initialLoad = os.loadavg(); +const results = []; +for (const mode of ["prepared", "legacy"]) { + for (const fixture of cases) { + const before = v8.deserialize(v8.serialize(fixture.root)); + const original = build(baseline, fixture, mode); + const ported = build(candidate, fixture, mode); + assert.deepEqual(ported(fixture.root), original(fixture.root), fixture.name); + let count = 100; + while (Math.min(batch(original, fixture.root, count), batch(ported, fixture.root, count)) * count < targetSampleMs * 1e6) { + count *= 2; + } + const measurements = []; + for (let i = 0; i < samples; i++) { + let baselineNs, candidateNs; + if (i % 2) { + candidateNs = batch(ported, fixture.root, count); + baselineNs = batch(original, fixture.root, count); + } else { + baselineNs = batch(original, fixture.root, count); + candidateNs = batch(ported, fixture.root, count); + } + measurements.push({baselineNs, candidateNs}); + } + assert.deepEqual(fixture.root, before, fixture.name + ": input mutated"); + const result = { + mode, + name: fixture.name, + count, + baselineNs: median(measurements.map(sample => sample.baselineNs)), + candidateNs: median(measurements.map(sample => sample.candidateNs)), + ratio: median(measurements.map(sample => sample.candidateNs / sample.baselineNs)), + samples: measurements, + }; + results.push(result); + console.log(mode, fixture.name, Math.round(result.baselineNs), Math.round(result.candidateNs), (result.ratio * 100 - 100).toFixed(1) + "%"); + } +} +const report = { + fixtureVersion: 3, + node: process.version, + cpu: os.cpus()[0].model, + samples, + targetSampleMs, + initialLoad, + finalLoad: os.loadavg(), + sha256: { + baseline: hash("../../src/utils"), + preparedBaseline: hash("../../src/prepareConversion"), + candidate: hash("./output/utils.cjs"), + fixtures: hash("../fixtures"), + }, + results, +}; +fs.writeFileSync(process.argv[2], JSON.stringify(report, null, 2) + "\n"); +if (!sink) throw new Error("Missing benchmark result"); diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/results/paired-final.json b/packages/rescript-relay/benchmarks/rescript-runtime/results/paired-final.json new file mode 100644 index 00000000..afb82854 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/results/paired-final.json @@ -0,0 +1,2437 @@ +{ + "fixtureVersion": 3, + "node": "v24.16.0", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 31, + "targetSampleMs": 20, + "initialLoad": [ + 20.68, + 21.39, + 18.74 + ], + "finalLoad": [ + 19.18, + 20.96, + 18.69 + ], + "sha256": { + "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", + "candidate": "efdf597c559c9b77f3d07ec1c3887eb37708d373d4f820250af2436ce39a08ea", + "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" + }, + "results": [ + { + "mode": "prepared", + "name": "small fragment", + "count": 409600, + "baselineNs": 102.4374340820311, + "candidateNs": 91.70031738281237, + "ratio": 0.9006024123311214, + "samples": [ + { + "baselineNs": 109.94234130859377, + "candidateNs": 97.37760253906255 + }, + { + "baselineNs": 105.10208984375005, + "candidateNs": 93.7282250976562 + }, + { + "baselineNs": 106.64225830078131, + "candidateNs": 98.2967236328125 + }, + { + "baselineNs": 114.22939941406251, + "candidateNs": 167.64104248046863 + }, + { + "baselineNs": 107.84939697265627, + "candidateNs": 130.96789794921875 + }, + { + "baselineNs": 99.29998535156248, + "candidateNs": 117.90455810546884 + }, + { + "baselineNs": 107.66093017578137, + "candidateNs": 90.97561035156242 + }, + { + "baselineNs": 112.22089111328133, + "candidateNs": 91.4827954101563 + }, + { + "baselineNs": 154.84508056640615, + "candidateNs": 153.66682617187544 + }, + { + "baselineNs": 114.05191406250015, + "candidateNs": 104.93644531249956 + }, + { + "baselineNs": 104.63494628906277, + "candidateNs": 94.05853515625007 + }, + { + "baselineNs": 97.82815917968757, + "candidateNs": 89.56975341796846 + }, + { + "baselineNs": 98.48533691406259, + "candidateNs": 90.70725585937467 + }, + { + "baselineNs": 99.30081787109357, + "candidateNs": 97.82077392578135 + }, + { + "baselineNs": 168.26986816406264, + "candidateNs": 92.43425048828136 + }, + { + "baselineNs": 101.72140869140645, + "candidateNs": 89.448603515625 + }, + { + "baselineNs": 101.05002197265622, + "candidateNs": 91.00589355468702 + }, + { + "baselineNs": 98.11576416015654, + "candidateNs": 89.46132324218759 + }, + { + "baselineNs": 97.67626220703096, + "candidateNs": 87.0336865234378 + }, + { + "baselineNs": 98.87944091796886, + "candidateNs": 91.70031738281237 + }, + { + "baselineNs": 167.2362255859372, + "candidateNs": 98.3479174804691 + }, + { + "baselineNs": 102.95070800781292, + "candidateNs": 91.51691650390647 + }, + { + "baselineNs": 102.4374340820311, + "candidateNs": 92.99651855468773 + }, + { + "baselineNs": 100.45732421875009, + "candidateNs": 90.6966894531247 + }, + { + "baselineNs": 98.08325683593688, + "candidateNs": 88.19584228515586 + }, + { + "baselineNs": 99.61608642578112, + "candidateNs": 87.14471191406227 + }, + { + "baselineNs": 167.0240307617188, + "candidateNs": 88.94359619140647 + }, + { + "baselineNs": 110.56950439453094, + "candidateNs": 95.71288330078143 + }, + { + "baselineNs": 99.8858837890626, + "candidateNs": 94.03823486328177 + }, + { + "baselineNs": 101.0484082031249, + "candidateNs": 91.09568603515639 + }, + { + "baselineNs": 98.72448486328067, + "candidateNs": 88.51991943359282 + } + ] + }, + { + "mode": "prepared", + "name": "unchanged object", + "count": 409600, + "baselineNs": 55.89947509765713, + "candidateNs": 44.29194091796873, + "ratio": 0.7933846994786131, + "samples": [ + { + "baselineNs": 97.59392822265566, + "candidateNs": 44.561713867187215 + }, + { + "baselineNs": 55.46484130859452, + "candidateNs": 45.604702148438484 + }, + { + "baselineNs": 55.130175781249456, + "candidateNs": 44.460349121093756 + }, + { + "baselineNs": 56.38545410156293, + "candidateNs": 44.06798339843809 + }, + { + "baselineNs": 55.0174853515617, + "candidateNs": 46.18489990234398 + }, + { + "baselineNs": 55.83619628906189, + "candidateNs": 43.6313159179691 + }, + { + "baselineNs": 55.53902832031277, + "candidateNs": 43.98212646484434 + }, + { + "baselineNs": 57.06077636718709, + "candidateNs": 43.416262207031096 + }, + { + "baselineNs": 57.15270019531204, + "candidateNs": 43.707045898436775 + }, + { + "baselineNs": 56.14256347656221, + "candidateNs": 44.2775097656245 + }, + { + "baselineNs": 55.40562255859416, + "candidateNs": 43.805034179688064 + }, + { + "baselineNs": 103.50011230468748, + "candidateNs": 44.71405273437479 + }, + { + "baselineNs": 62.32186767578196, + "candidateNs": 44.296611328125124 + }, + { + "baselineNs": 54.531901855467964, + "candidateNs": 43.81775390625009 + }, + { + "baselineNs": 54.96553466796783, + "candidateNs": 44.25605712890634 + }, + { + "baselineNs": 54.822585449219034, + "candidateNs": 44.90875488281309 + }, + { + "baselineNs": 55.98484375000101, + "candidateNs": 44.41835205078126 + }, + { + "baselineNs": 55.89947509765713, + "candidateNs": 45.59667724609362 + }, + { + "baselineNs": 58.67748046875065, + "candidateNs": 44.16139648437567 + }, + { + "baselineNs": 53.94333740234459, + "candidateNs": 46.04916748046972 + }, + { + "baselineNs": 56.24348388671874, + "candidateNs": 44.03249023437472 + }, + { + "baselineNs": 54.03738769531264, + "candidateNs": 44.078181152342744 + }, + { + "baselineNs": 54.60914550781237, + "candidateNs": 45.171850585937754 + }, + { + "baselineNs": 82.48651855468746, + "candidateNs": 76.32164306640598 + }, + { + "baselineNs": 54.724963378905976, + "candidateNs": 44.29194091796873 + }, + { + "baselineNs": 54.55870849609301, + "candidateNs": 43.94565673828011 + }, + { + "baselineNs": 56.13421875000135, + "candidateNs": 44.53603027343655 + }, + { + "baselineNs": 54.95953857421965, + "candidateNs": 43.217570800782035 + }, + { + "baselineNs": 57.821540527343004, + "candidateNs": 45.01643066406436 + }, + { + "baselineNs": 56.61731201171971, + "candidateNs": 51.750031738280185 + }, + { + "baselineNs": 56.09936523437442, + "candidateNs": 43.87711914062509 + } + ] + }, + { + "mode": "prepared", + "name": "nullable query", + "count": 204800, + "baselineNs": 148.93603515625298, + "candidateNs": 123.57809570312739, + "ratio": 0.8220193300149227, + "samples": [ + { + "baselineNs": 137.85943847656412, + "candidateNs": 161.1355566406214 + }, + { + "baselineNs": 141.3651855468734, + "candidateNs": 182.12513183593958 + }, + { + "baselineNs": 141.24527832031663, + "candidateNs": 115.42738769531269 + }, + { + "baselineNs": 144.36205566406014, + "candidateNs": 116.54943847656085 + }, + { + "baselineNs": 146.07208007812568, + "candidateNs": 113.64991210937701 + }, + { + "baselineNs": 189.08580078125237, + "candidateNs": 127.03736816406241 + }, + { + "baselineNs": 153.34236328125252, + "candidateNs": 124.94743652343932 + }, + { + "baselineNs": 148.20183593749815, + "candidateNs": 127.25051757812356 + }, + { + "baselineNs": 152.25926269531342, + "candidateNs": 123.57809570312739 + }, + { + "baselineNs": 253.0050927734351, + "candidateNs": 114.87795898437625 + }, + { + "baselineNs": 158.63689453125218, + "candidateNs": 116.46851562499894 + }, + { + "baselineNs": 154.48460937500298, + "candidateNs": 117.33979003906381 + }, + { + "baselineNs": 152.54422363280895, + "candidateNs": 115.03123046874731 + }, + { + "baselineNs": 145.42803710937412, + "candidateNs": 115.33165039062433 + }, + { + "baselineNs": 143.7753515624962, + "candidateNs": 118.1861181640631 + }, + { + "baselineNs": 152.97956542968726, + "candidateNs": 116.4766894531244 + }, + { + "baselineNs": 145.8647021484394, + "candidateNs": 125.69714355468608 + }, + { + "baselineNs": 145.01812988281236, + "candidateNs": 122.22926269531254 + }, + { + "baselineNs": 211.81381347656458, + "candidateNs": 171.66987304687353 + }, + { + "baselineNs": 142.65536621093756, + "candidateNs": 126.83263671875 + }, + { + "baselineNs": 138.2356835937504, + "candidateNs": 112.17133300781333 + }, + { + "baselineNs": 140.00885742187384, + "candidateNs": 116.64404785156623 + }, + { + "baselineNs": 148.62758789062624, + "candidateNs": 155.63967285156187 + }, + { + "baselineNs": 166.79527832031306, + "candidateNs": 113.57109863281423 + }, + { + "baselineNs": 152.78618652343923, + "candidateNs": 126.67677734374827 + }, + { + "baselineNs": 146.36462402343398, + "candidateNs": 123.19519531249767 + }, + { + "baselineNs": 148.93603515625298, + "candidateNs": 157.4605908203086 + }, + { + "baselineNs": 150.28032714843764, + "candidateNs": 191.7699218750002 + }, + { + "baselineNs": 167.9802783203099, + "candidateNs": 144.6338574218764 + }, + { + "baselineNs": 150.73587402343767, + "candidateNs": 137.21172363281298 + }, + { + "baselineNs": 151.84823242187394, + "candidateNs": 125.80442871093834 + } + ] + }, + { + "mode": "prepared", + "name": "connection / 100 rows", + "count": 1600, + "baselineNs": 21940.737499999726, + "candidateNs": 18028.042500000083, + "ratio": 0.8210054435040013, + "samples": [ + { + "baselineNs": 20359.61812500034, + "candidateNs": 20860.72124999987 + }, + { + "baselineNs": 30255.709374999926, + "candidateNs": 17592.882499999974 + }, + { + "baselineNs": 25797.633750000274, + "candidateNs": 16821.530624999923 + }, + { + "baselineNs": 19738.913125000297, + "candidateNs": 16933.64875000043 + }, + { + "baselineNs": 19941.835000000196, + "candidateNs": 18425.186874999894 + }, + { + "baselineNs": 19420.26124999984, + "candidateNs": 17148.7806250002 + }, + { + "baselineNs": 19520.206249999886, + "candidateNs": 17446.70625000026 + }, + { + "baselineNs": 19488.885000000097, + "candidateNs": 16195.704374999877 + }, + { + "baselineNs": 19489.285624999866, + "candidateNs": 16682.881249999467 + }, + { + "baselineNs": 26959.892500000253, + "candidateNs": 16328.54312500001 + }, + { + "baselineNs": 29504.78374999989, + "candidateNs": 18028.042500000083 + }, + { + "baselineNs": 21151.183124999876, + "candidateNs": 16589.39250000003 + }, + { + "baselineNs": 20723.862500000225, + "candidateNs": 20350.406874999862 + }, + { + "baselineNs": 21940.737499999726, + "candidateNs": 18964.62499999984 + }, + { + "baselineNs": 20425.82437500016, + "candidateNs": 17016.50562499992 + }, + { + "baselineNs": 20026.38187499997, + "candidateNs": 16858.21312499968 + }, + { + "baselineNs": 19837.75062500001, + "candidateNs": 16286.901249999913 + }, + { + "baselineNs": 48972.81062500042, + "candidateNs": 16388.71875000007 + }, + { + "baselineNs": 20970.647500000152, + "candidateNs": 16259.862499999825 + }, + { + "baselineNs": 21309.43187500009, + "candidateNs": 16203.224375000218 + }, + { + "baselineNs": 20748.020624999983, + "candidateNs": 23270.93312499983 + }, + { + "baselineNs": 29345.27000000003, + "candidateNs": 21307.96625000016 + }, + { + "baselineNs": 24612.93812500003, + "candidateNs": 21998.778125000055 + }, + { + "baselineNs": 25418.040625000343, + "candidateNs": 22301.012500000183 + }, + { + "baselineNs": 32679.628125000025, + "candidateNs": 25176.7537500001 + }, + { + "baselineNs": 30602.909374999857, + "candidateNs": 24613.814374999947 + }, + { + "baselineNs": 29983.933125000134, + "candidateNs": 25708.765624999614 + }, + { + "baselineNs": 29028.239374999885, + "candidateNs": 20078.14812499987 + }, + { + "baselineNs": 30743.42499999943, + "candidateNs": 20474.741874999156 + }, + { + "baselineNs": 31063.25437500004, + "candidateNs": 20345.54125 + }, + { + "baselineNs": 37214.77437499971, + "candidateNs": 22552.487499999643 + } + ] + }, + { + "mode": "prepared", + "name": "plural fragment / 100 rows", + "count": 1600, + "baselineNs": 15024.559375000308, + "candidateNs": 12962.843749999138, + "ratio": 0.8388993027599011, + "samples": [ + { + "baselineNs": 20039.65687499999, + "candidateNs": 16424.23624999992 + }, + { + "baselineNs": 20096.51437499997, + "candidateNs": 17686.11437499999 + }, + { + "baselineNs": 24327.598749999877, + "candidateNs": 15444.076874999837 + }, + { + "baselineNs": 15024.559375000308, + "candidateNs": 13197.688125000013 + }, + { + "baselineNs": 15903.013125000598, + "candidateNs": 12979.050000000141 + }, + { + "baselineNs": 32338.839999999895, + "candidateNs": 18736.60000000086 + }, + { + "baselineNs": 14792.79687500025, + "candidateNs": 12825.772499999175 + }, + { + "baselineNs": 15493.864999999689, + "candidateNs": 14616.638124999781 + }, + { + "baselineNs": 14846.178125000051, + "candidateNs": 12237.898749999658 + }, + { + "baselineNs": 15038.228749999687, + "candidateNs": 13266.411250000376 + }, + { + "baselineNs": 15038.053750000698, + "candidateNs": 13986.153124999419 + }, + { + "baselineNs": 16505.4525000005, + "candidateNs": 14472.1281249997 + }, + { + "baselineNs": 17360.468125000352, + "candidateNs": 12917.051250000215 + }, + { + "baselineNs": 15566.8656250009, + "candidateNs": 13091.230625000208 + }, + { + "baselineNs": 14664.346875000547, + "candidateNs": 13486.759375000474 + }, + { + "baselineNs": 26451.34437500019, + "candidateNs": 12058.772499999577 + }, + { + "baselineNs": 20010.4518750004, + "candidateNs": 12298.870624999838 + }, + { + "baselineNs": 14235.004375000244, + "candidateNs": 12233.377500000415 + }, + { + "baselineNs": 14404.982500000186, + "candidateNs": 13817.790624999589 + }, + { + "baselineNs": 14016.360000000532, + "candidateNs": 11580.362500000094 + }, + { + "baselineNs": 14522.705000000542, + "candidateNs": 12023.437500000682 + }, + { + "baselineNs": 13868.424374999222, + "candidateNs": 11688.829375000296 + }, + { + "baselineNs": 14863.53000000008, + "candidateNs": 11776.28249999998 + }, + { + "baselineNs": 14366.264999999887, + "candidateNs": 11842.851874999951 + }, + { + "baselineNs": 14165.13499999951, + "candidateNs": 11883.12187499946 + }, + { + "baselineNs": 14031.645625000237, + "candidateNs": 11743.420625000454 + }, + { + "baselineNs": 18998.802500000238, + "candidateNs": 23991.037499999948 + }, + { + "baselineNs": 15176.671875000238, + "candidateNs": 18113.32187499943 + }, + { + "baselineNs": 14734.148124999821, + "candidateNs": 12041.689999999791 + }, + { + "baselineNs": 14541.93499999974, + "candidateNs": 12962.843749999138 + }, + { + "baselineNs": 14179.568749999591, + "candidateNs": 11785.236875000463 + } + ] + }, + { + "mode": "prepared", + "name": "union list / 100 rows", + "count": 1600, + "baselineNs": 18634.26312499996, + "candidateNs": 14601.722500000276, + "ratio": 0.8197016737223956, + "samples": [ + { + "baselineNs": 18972.52750000007, + "candidateNs": 14239.913750000142 + }, + { + "baselineNs": 18421.379999999772, + "candidateNs": 14838.044374999981 + }, + { + "baselineNs": 18617.475000000923, + "candidateNs": 14360.341875000131 + }, + { + "baselineNs": 24171.028125000474, + "candidateNs": 22540.9406250003 + }, + { + "baselineNs": 18653.66250000079, + "candidateNs": 14359.558749999904 + }, + { + "baselineNs": 19526.386874999844, + "candidateNs": 14505.17125000033 + }, + { + "baselineNs": 24572.761874999287, + "candidateNs": 13988.295000000335 + }, + { + "baselineNs": 18628.120624999836, + "candidateNs": 14459.065624999994 + }, + { + "baselineNs": 18279.718124999818, + "candidateNs": 16714.15937500001 + }, + { + "baselineNs": 16520.76875000034, + "candidateNs": 14681.273125000871 + }, + { + "baselineNs": 17573.92125000024, + "candidateNs": 14993.10625000021 + }, + { + "baselineNs": 19809.47812499949, + "candidateNs": 16282.743749999327 + }, + { + "baselineNs": 22875.159374999614, + "candidateNs": 25305.784999999334 + }, + { + "baselineNs": 16622.71124999961, + "candidateNs": 14798.181249999516 + }, + { + "baselineNs": 16422.9899999998, + "candidateNs": 14507.588124999984 + }, + { + "baselineNs": 19595.85500000003, + "candidateNs": 15897.615625000299 + }, + { + "baselineNs": 19145.53562500032, + "candidateNs": 14096.392500000547 + }, + { + "baselineNs": 18500.422500000015, + "candidateNs": 14204.102500000317 + }, + { + "baselineNs": 18940.792500000043, + "candidateNs": 14565.448125000556 + }, + { + "baselineNs": 17199.41375000076, + "candidateNs": 14878.65250000027 + }, + { + "baselineNs": 17673.853750000035, + "candidateNs": 14487.287499999866 + }, + { + "baselineNs": 32536.432499999817, + "candidateNs": 15202.458124999794 + }, + { + "baselineNs": 19627.960000000257, + "candidateNs": 17209.858749999967 + }, + { + "baselineNs": 16889.121250000015, + "candidateNs": 14601.722500000276 + }, + { + "baselineNs": 19568.50374999931, + "candidateNs": 15149.107500000127 + }, + { + "baselineNs": 18684.332499999527, + "candidateNs": 14591.127499999177 + }, + { + "baselineNs": 18634.26312499996, + "candidateNs": 14460.824999999886 + }, + { + "baselineNs": 16880.49812500026, + "candidateNs": 14673.126875001117 + }, + { + "baselineNs": 16776.232500000104, + "candidateNs": 14197.414999999864 + }, + { + "baselineNs": 16943.473750000067, + "candidateNs": 14232.80624999961 + }, + { + "baselineNs": 20294.88937499991, + "candidateNs": 27976.244374999624 + } + ] + }, + { + "mode": "prepared", + "name": "custom scalar list", + "count": 3200, + "baselineNs": 11663.735624999845, + "candidateNs": 11913.714062499706, + "ratio": 1.02246230509656, + "samples": [ + { + "baselineNs": 13104.420937499981, + "candidateNs": 11844.64593750022 + }, + { + "baselineNs": 11714.271562499902, + "candidateNs": 12057.946250000101 + }, + { + "baselineNs": 11771.652187500196, + "candidateNs": 13509.677499999954 + }, + { + "baselineNs": 15195.369687500033, + "candidateNs": 13185.261250000054 + }, + { + "baselineNs": 14034.475625000481, + "candidateNs": 12021.132812500355 + }, + { + "baselineNs": 11663.735624999845, + "candidateNs": 11640.181562500515 + }, + { + "baselineNs": 12445.168749999879, + "candidateNs": 12728.162812500159 + }, + { + "baselineNs": 11562.89500000014, + "candidateNs": 11759.804375000158 + }, + { + "baselineNs": 11526.291562500433, + "candidateNs": 11657.163749999881 + }, + { + "baselineNs": 11332.105312500289, + "candidateNs": 11591.636874999835 + }, + { + "baselineNs": 17037.895937500027, + "candidateNs": 12781.091250000145 + }, + { + "baselineNs": 11296.619999999963, + "candidateNs": 11550.368124999863 + }, + { + "baselineNs": 11609.12906250019, + "candidateNs": 11645.119062500271 + }, + { + "baselineNs": 11484.455937500117, + "candidateNs": 11906.331562499872 + }, + { + "baselineNs": 11606.777812500013, + "candidateNs": 11765.534062500366 + }, + { + "baselineNs": 11833.910312499826, + "candidateNs": 11784.28218750014 + }, + { + "baselineNs": 11672.536562500114, + "candidateNs": 18533.369374999893 + }, + { + "baselineNs": 11586.223437499826, + "candidateNs": 13151.350312500086 + }, + { + "baselineNs": 12050.904687499722, + "candidateNs": 11913.714062499706 + }, + { + "baselineNs": 11367.700937499876, + "candidateNs": 11716.535312500015 + }, + { + "baselineNs": 11413.97281249965, + "candidateNs": 12370.092499999713 + }, + { + "baselineNs": 11358.871874999748, + "candidateNs": 12500.83625000002 + }, + { + "baselineNs": 11260.072499999866, + "candidateNs": 11864.351875000237 + }, + { + "baselineNs": 11414.27031250032, + "candidateNs": 18651.317187499786 + }, + { + "baselineNs": 12318.707499999846, + "candidateNs": 11815.597500000196 + }, + { + "baselineNs": 11238.465937499881, + "candidateNs": 11880.062812500115 + }, + { + "baselineNs": 11319.168750000017, + "candidateNs": 11492.680937500381 + }, + { + "baselineNs": 11977.907500000241, + "candidateNs": 12307.007499999827 + }, + { + "baselineNs": 11681.52531249973, + "candidateNs": 12489.1018750003 + }, + { + "baselineNs": 15664.077499999963, + "candidateNs": 15516.251250000438 + }, + { + "baselineNs": 14271.038437499898, + "candidateNs": 13638.790312500078 + } + ] + }, + { + "mode": "prepared", + "name": "opaque JSON list", + "count": 51200, + "baselineNs": 441.32806640622135, + "candidateNs": 538.5150781249947, + "ratio": 1.2004831145919181, + "samples": [ + { + "baselineNs": 440.8327929687772, + "candidateNs": 523.2655468750024 + }, + { + "baselineNs": 439.28455078123824, + "candidateNs": 511.2383203125148 + }, + { + "baselineNs": 433.41644531249557, + "candidateNs": 520.7713867187281 + }, + { + "baselineNs": 420.8522656249869, + "candidateNs": 518.2329882812198 + }, + { + "baselineNs": 441.32806640622135, + "candidateNs": 592.3081640624872 + }, + { + "baselineNs": 464.08630859374966, + "candidateNs": 662.4395312500296 + }, + { + "baselineNs": 435.6812500000018, + "candidateNs": 526.524062500009 + }, + { + "baselineNs": 436.83011718751885, + "candidateNs": 527.8083203124951 + }, + { + "baselineNs": 434.536718749996, + "candidateNs": 547.9375781249729 + }, + { + "baselineNs": 465.4555078125, + "candidateNs": 534.9953320312295 + }, + { + "baselineNs": 459.19171874999165, + "candidateNs": 555.1512109374812 + }, + { + "baselineNs": 469.99748046872014, + "candidateNs": 569.3426757812503 + }, + { + "baselineNs": 469.4278515624717, + "candidateNs": 552.409707031245 + }, + { + "baselineNs": 512.0644921874984, + "candidateNs": 563.0489453124809 + }, + { + "baselineNs": 601.2666796874911, + "candidateNs": 706.9292773437396 + }, + { + "baselineNs": 457.85929687500726, + "candidateNs": 573.1299218750152 + }, + { + "baselineNs": 479.8366015625177, + "candidateNs": 587.9066601562499 + }, + { + "baselineNs": 518.061953125013, + "candidateNs": 600.2937695312482 + }, + { + "baselineNs": 519.6924023437432, + "candidateNs": 626.7192773437813 + }, + { + "baselineNs": 485.5620507812475, + "candidateNs": 613.0240625000027 + }, + { + "baselineNs": 474.68564453126305, + "candidateNs": 564.886406250018 + }, + { + "baselineNs": 440.98171874999537, + "candidateNs": 509.18757812500104 + }, + { + "baselineNs": 436.0827929687616, + "candidateNs": 538.5150781249947 + }, + { + "baselineNs": 614.3081249999938, + "candidateNs": 617.4286718749755 + }, + { + "baselineNs": 465.15533203123744, + "candidateNs": 510.7692773437477 + }, + { + "baselineNs": 425.8499999999898, + "candidateNs": 518.2672460937355 + }, + { + "baselineNs": 427.6052539062647, + "candidateNs": 511.00058593746667 + }, + { + "baselineNs": 434.6862109374782, + "candidateNs": 505.33478515625063 + }, + { + "baselineNs": 429.09968749999194, + "candidateNs": 505.5398632812569 + }, + { + "baselineNs": 424.09548828121757, + "candidateNs": 509.11947265621643 + }, + { + "baselineNs": 439.968261718775, + "candidateNs": 505.98777343751067 + } + ] + }, + { + "mode": "prepared", + "name": "recursive inputs", + "count": 1600, + "baselineNs": 16857.66187499894, + "candidateNs": 14194.308749999891, + "ratio": 0.8569818680573524, + "samples": [ + { + "baselineNs": 24157.3268749994, + "candidateNs": 22282.502499999733 + }, + { + "baselineNs": 17043.03062500003, + "candidateNs": 14627.23937499959 + }, + { + "baselineNs": 19114.10124999975, + "candidateNs": 14265.355625000211 + }, + { + "baselineNs": 16303.789374999269, + "candidateNs": 13972.051875000489 + }, + { + "baselineNs": 17096.268749999126, + "candidateNs": 15072.40000000138 + }, + { + "baselineNs": 16586.98749999985, + "candidateNs": 14602.599375000409 + }, + { + "baselineNs": 17052.178750000166, + "candidateNs": 15891.57937500204 + }, + { + "baselineNs": 19432.803125000646, + "candidateNs": 16284.446875001777 + }, + { + "baselineNs": 17408.614999999372, + "candidateNs": 14927.645000000211 + }, + { + "baselineNs": 29361.619374999464, + "candidateNs": 17280.510625000716 + }, + { + "baselineNs": 19070.424999999886, + "candidateNs": 14151.302500001748 + }, + { + "baselineNs": 16004.850000001625, + "candidateNs": 14194.308749999891 + }, + { + "baselineNs": 17173.871874999804, + "candidateNs": 14132.18499999857 + }, + { + "baselineNs": 16524.51312500034, + "candidateNs": 13603.072500000053 + }, + { + "baselineNs": 16404.642499999227, + "candidateNs": 14209.850624999945 + }, + { + "baselineNs": 15866.406874999939, + "candidateNs": 14147.319999999581 + }, + { + "baselineNs": 15889.105624999047, + "candidateNs": 13624.331875000737 + }, + { + "baselineNs": 16058.751250000114, + "candidateNs": 13654.300625000815 + }, + { + "baselineNs": 15863.269374999618, + "candidateNs": 13812.643750000007 + }, + { + "baselineNs": 24910.675625001208, + "candidateNs": 22387.08062500109 + }, + { + "baselineNs": 16172.58562500183, + "candidateNs": 13524.937499998941 + }, + { + "baselineNs": 16109.847499999432, + "candidateNs": 13677.545000000464 + }, + { + "baselineNs": 16171.119999999064, + "candidateNs": 13502.833125000961 + }, + { + "baselineNs": 17074.35250000117, + "candidateNs": 14573.694375001196 + }, + { + "baselineNs": 17343.924374999915, + "candidateNs": 14163.738750000903 + }, + { + "baselineNs": 16857.66187499894, + "candidateNs": 13778.541874999064 + }, + { + "baselineNs": 16494.693750000806, + "candidateNs": 13728.209374999096 + }, + { + "baselineNs": 16570.07437499942, + "candidateNs": 13386.175625000758 + }, + { + "baselineNs": 17378.471249999166, + "candidateNs": 20003.506875000312 + }, + { + "baselineNs": 16931.557500001873, + "candidateNs": 25859.69999999861 + }, + { + "baselineNs": 16685.373124998932, + "candidateNs": 15307.688124999004 + } + ] + }, + { + "mode": "legacy", + "name": "small fragment", + "count": 102400, + "baselineNs": 263.53763671874475, + "candidateNs": 255.13298828126807, + "ratio": 0.9817418609062459, + "samples": [ + { + "baselineNs": 258.73941406249656, + "candidateNs": 244.9315722656209 + }, + { + "baselineNs": 266.5002832031149, + "candidateNs": 246.17386718752243 + }, + { + "baselineNs": 264.80283203127897, + "candidateNs": 251.48429687501306 + }, + { + "baselineNs": 253.63826171872716, + "candidateNs": 251.6994531250205 + }, + { + "baselineNs": 249.48050781247844, + "candidateNs": 252.37386718750088 + }, + { + "baselineNs": 280.17132812500734, + "candidateNs": 462.2243945312477 + }, + { + "baselineNs": 250.23300781249702, + "candidateNs": 245.664218750008 + }, + { + "baselineNs": 259.3158984375066, + "candidateNs": 239.8107714843789 + }, + { + "baselineNs": 254.9596093749784, + "candidateNs": 246.0752441406555 + }, + { + "baselineNs": 255.7985937500007, + "candidateNs": 246.2135937500065 + }, + { + "baselineNs": 256.5203710937425, + "candidateNs": 255.13298828126807 + }, + { + "baselineNs": 300.71591796872355, + "candidateNs": 297.79379882810986 + }, + { + "baselineNs": 260.60906249998794, + "candidateNs": 262.29780273439474 + }, + { + "baselineNs": 348.1220214844072, + "candidateNs": 252.86914062498056 + }, + { + "baselineNs": 435.9715625000149, + "candidateNs": 251.33108398438964 + }, + { + "baselineNs": 263.2776855468677, + "candidateNs": 260.92156249998055 + }, + { + "baselineNs": 260.4179785156191, + "candidateNs": 257.34752929690075 + }, + { + "baselineNs": 263.53763671874475, + "candidateNs": 261.171455078113 + }, + { + "baselineNs": 265.36472656250254, + "candidateNs": 253.7844433593861 + }, + { + "baselineNs": 261.387578125003, + "candidateNs": 256.28566406247444 + }, + { + "baselineNs": 266.49058593751107, + "candidateNs": 260.13903320311726 + }, + { + "baselineNs": 272.0723339843545, + "candidateNs": 276.69855468751337 + }, + { + "baselineNs": 279.7933593749846, + "candidateNs": 343.9171972656041 + }, + { + "baselineNs": 266.836464843756, + "candidateNs": 413.6512402343939 + }, + { + "baselineNs": 286.5626074218852, + "candidateNs": 268.6473046875193 + }, + { + "baselineNs": 270.45736328123127, + "candidateNs": 314.12964843749336 + }, + { + "baselineNs": 259.6044238281081, + "candidateNs": 252.11410156252612 + }, + { + "baselineNs": 269.32924804686564, + "candidateNs": 252.63666015625574 + }, + { + "baselineNs": 266.77951171876657, + "candidateNs": 268.0229785156385 + }, + { + "baselineNs": 262.2950585937289, + "candidateNs": 267.26451171875 + }, + { + "baselineNs": 260.709345703134, + "candidateNs": 244.45499999998788 + } + ] + }, + { + "mode": "legacy", + "name": "unchanged object", + "count": 102400, + "baselineNs": 111.38375976564419, + "candidateNs": 110.24087890621814, + "ratio": 0.9926745976948665, + "samples": [ + { + "baselineNs": 144.83859374998076, + "candidateNs": 112.44680664063365 + }, + { + "baselineNs": 108.16928710937646, + "candidateNs": 109.61136718748321 + }, + { + "baselineNs": 114.8605468750219, + "candidateNs": 112.46491210936682 + }, + { + "baselineNs": 112.7108789062703, + "candidateNs": 114.32193359372178 + }, + { + "baselineNs": 112.51381835936769, + "candidateNs": 111.68960937499861 + }, + { + "baselineNs": 122.57160156249114, + "candidateNs": 124.43147460935222 + }, + { + "baselineNs": 112.95890625000027, + "candidateNs": 109.3335937499873 + }, + { + "baselineNs": 110.64398437500955, + "candidateNs": 109.21041015624411 + }, + { + "baselineNs": 111.80575195311349, + "candidateNs": 110.02464843748783 + }, + { + "baselineNs": 109.44542968751136, + "candidateNs": 110.24087890621814 + }, + { + "baselineNs": 107.82263671874404, + "candidateNs": 108.3128222656171 + }, + { + "baselineNs": 107.91734375001028, + "candidateNs": 108.99722656247944 + }, + { + "baselineNs": 122.71630859377325, + "candidateNs": 113.26573242186554 + }, + { + "baselineNs": 111.38375976564419, + "candidateNs": 112.89500976563005 + }, + { + "baselineNs": 114.41077148436563, + "candidateNs": 108.87452148434562 + }, + { + "baselineNs": 109.25982421873925, + "candidateNs": 109.04251953125055 + }, + { + "baselineNs": 109.45110351560317, + "candidateNs": 110.43323242187597 + }, + { + "baselineNs": 110.50504882813783, + "candidateNs": 108.61622070311938 + }, + { + "baselineNs": 118.52616210937583, + "candidateNs": 109.63386718749746 + }, + { + "baselineNs": 152.42979492189335, + "candidateNs": 109.96721679688905 + }, + { + "baselineNs": 197.68701171873462, + "candidateNs": 200.8624511718793 + }, + { + "baselineNs": 110.58821289061882, + "candidateNs": 129.6916113281199 + }, + { + "baselineNs": 111.37916015623972, + "candidateNs": 108.95182617186805 + }, + { + "baselineNs": 109.80802734376738, + "candidateNs": 110.33050781250607 + }, + { + "baselineNs": 109.42449218749317, + "candidateNs": 108.56583984374168 + }, + { + "baselineNs": 109.82319335937518, + "candidateNs": 109.4253710937565 + }, + { + "baselineNs": 114.26879882812102, + "candidateNs": 109.16022460936148 + }, + { + "baselineNs": 112.32156249999292, + "candidateNs": 110.52647460939369 + }, + { + "baselineNs": 113.92440429688122, + "candidateNs": 110.39712890624997 + }, + { + "baselineNs": 110.16446289062287, + "candidateNs": 115.51373046874147 + }, + { + "baselineNs": 109.84550781248714, + "candidateNs": 110.30437500000545 + } + ] + }, + { + "mode": "legacy", + "name": "nullable query", + "count": 102400, + "baselineNs": 446.55356445311156, + "candidateNs": 429.20505859374464, + "ratio": 0.9638199985851299, + "samples": [ + { + "baselineNs": 395.9141015625178, + "candidateNs": 500.8427929687542 + }, + { + "baselineNs": 395.90452148438254, + "candidateNs": 454.76860351563175 + }, + { + "baselineNs": 390.12787109374614, + "candidateNs": 384.7616796874931 + }, + { + "baselineNs": 393.50799804690695, + "candidateNs": 378.6349609374895 + }, + { + "baselineNs": 403.234384765625, + "candidateNs": 386.5271289062733 + }, + { + "baselineNs": 389.8585253906006, + "candidateNs": 378.15857421875876 + }, + { + "baselineNs": 389.396123046879, + "candidateNs": 461.2721093749883 + }, + { + "baselineNs": 397.21392578126574, + "candidateNs": 505.68642578127765 + }, + { + "baselineNs": 436.4853222656251, + "candidateNs": 382.2343457031252 + }, + { + "baselineNs": 415.46815429690304, + "candidateNs": 390.53617187502 + }, + { + "baselineNs": 406.281845703127, + "candidateNs": 405.21411132814933 + }, + { + "baselineNs": 449.9030566406148, + "candidateNs": 448.0689257812643 + }, + { + "baselineNs": 575.597177734366, + "candidateNs": 645.3925585937625 + }, + { + "baselineNs": 594.3539062499781, + "candidateNs": 432.7214648437305 + }, + { + "baselineNs": 495.794384765631, + "candidateNs": 452.2268945312291 + }, + { + "baselineNs": 542.0296191406493, + "candidateNs": 478.563974609365 + }, + { + "baselineNs": 468.6770214843605, + "candidateNs": 414.27458984372834 + }, + { + "baselineNs": 538.2812304687334, + "candidateNs": 565.4698242187806 + }, + { + "baselineNs": 430.0137109375157, + "candidateNs": 574.8401757812261 + }, + { + "baselineNs": 527.513808593767, + "candidateNs": 426.66050781249965 + }, + { + "baselineNs": 478.1846386718769, + "candidateNs": 408.0650000000219 + }, + { + "baselineNs": 609.4815234374806, + "candidateNs": 456.0169628906153 + }, + { + "baselineNs": 872.3532617187501, + "candidateNs": 423.7497265625123 + }, + { + "baselineNs": 490.43357421872713, + "candidateNs": 396.06096679687397 + }, + { + "baselineNs": 502.96819335937215, + "candidateNs": 413.76845703123166 + }, + { + "baselineNs": 446.55356445311156, + "candidateNs": 430.3972558593827 + }, + { + "baselineNs": 478.1127246093675, + "candidateNs": 392.86733398434137 + }, + { + "baselineNs": 519.2032812500003, + "candidateNs": 500.5407617187529 + }, + { + "baselineNs": 417.30708007811756, + "candidateNs": 435.14147460939506 + }, + { + "baselineNs": 432.7241113281133, + "candidateNs": 429.20505859374464 + }, + { + "baselineNs": 404.2670019531158, + "candidateNs": 395.92781250000536 + } + ] + }, + { + "mode": "legacy", + "name": "connection / 100 rows", + "count": 400, + "baselineNs": 64871.20750000031, + "candidateNs": 65180.14249999396, + "ratio": 1.0035241512219875, + "samples": [ + { + "baselineNs": 63230.53250000157, + "candidateNs": 61696.60749999821 + }, + { + "baselineNs": 106962.43749999667, + "candidateNs": 91770.22249999936 + }, + { + "baselineNs": 73929.72999999984, + "candidateNs": 65936.46999999692 + }, + { + "baselineNs": 64545.067500002915, + "candidateNs": 63723.68749999623 + }, + { + "baselineNs": 67135.76249999278, + "candidateNs": 64125.897499998246 + }, + { + "baselineNs": 64088.980000005904, + "candidateNs": 64585.34250000412 + }, + { + "baselineNs": 63144.192500003555, + "candidateNs": 64289.85999999896 + }, + { + "baselineNs": 62675.20750000586, + "candidateNs": 64724.4799999953 + }, + { + "baselineNs": 63325.287499992555, + "candidateNs": 62852.592499993996 + }, + { + "baselineNs": 61378.48000000304, + "candidateNs": 62256.36750000376 + }, + { + "baselineNs": 69902.51749999516, + "candidateNs": 104747.2474999995 + }, + { + "baselineNs": 63682.45999999999, + "candidateNs": 78835.97750000263 + }, + { + "baselineNs": 64362.019999998665, + "candidateNs": 61801.682499999515 + }, + { + "baselineNs": 61815.03249999878, + "candidateNs": 63428.68000000635 + }, + { + "baselineNs": 64746.172499999375, + "candidateNs": 64082.917499999894 + }, + { + "baselineNs": 62208.72500000041, + "candidateNs": 64151.99750000283 + }, + { + "baselineNs": 63352.034999998075, + "candidateNs": 64024.40750000096 + }, + { + "baselineNs": 64871.20750000031, + "candidateNs": 63776.51499999956 + }, + { + "baselineNs": 62714.9074999943, + "candidateNs": 63592.34249999645 + }, + { + "baselineNs": 87055.98749999808, + "candidateNs": 65180.14249999396 + }, + { + "baselineNs": 128476.62500000297, + "candidateNs": 69677.16499999369 + }, + { + "baselineNs": 64314.45500000336, + "candidateNs": 65291.47750000448 + }, + { + "baselineNs": 67812.51749999683, + "candidateNs": 73623.82749999597 + }, + { + "baselineNs": 77331.20750000126, + "candidateNs": 72873.33250000302 + }, + { + "baselineNs": 68976.8925000044, + "candidateNs": 69219.97749999719 + }, + { + "baselineNs": 72153.62249999998, + "candidateNs": 70196.04499999332 + }, + { + "baselineNs": 68115.61499999698, + "candidateNs": 68121.47749999895 + }, + { + "baselineNs": 66617.78499999855, + "candidateNs": 70424.47750000065 + }, + { + "baselineNs": 98062.96750000001, + "candidateNs": 103382.06999999784 + }, + { + "baselineNs": 66384.99249999768, + "candidateNs": 67642.16999999917 + }, + { + "baselineNs": 70518.782500003, + "candidateNs": 69587.92250000442 + } + ] + }, + { + "mode": "legacy", + "name": "plural fragment / 100 rows", + "count": 800, + "baselineNs": 26386.908749996113, + "candidateNs": 27629.483750001782, + "ratio": 1.0432064553896991, + "samples": [ + { + "baselineNs": 27532.587499999863, + "candidateNs": 27844.713750000665 + }, + { + "baselineNs": 26901.695000001382, + "candidateNs": 28444.586249997883 + }, + { + "baselineNs": 26669.1687499997, + "candidateNs": 27974.93624999788 + }, + { + "baselineNs": 26221.67250000075, + "candidateNs": 28121.02374999995 + }, + { + "baselineNs": 25979.79000000123, + "candidateNs": 29486.442499996883 + }, + { + "baselineNs": 49468.54625000015, + "candidateNs": 39989.70625000311 + }, + { + "baselineNs": 28890.252500000315, + "candidateNs": 28146.610000003417 + }, + { + "baselineNs": 27164.804999997617, + "candidateNs": 26535.0137500036 + }, + { + "baselineNs": 26588.79124999657, + "candidateNs": 28754.77250000131 + }, + { + "baselineNs": 25490.29000000246, + "candidateNs": 26483.17874999975 + }, + { + "baselineNs": 26794.942500000616, + "candidateNs": 27989.65124999995 + }, + { + "baselineNs": 28065.281250001135, + "candidateNs": 26820.72875000358 + }, + { + "baselineNs": 25929.08124999667, + "candidateNs": 26617.044999998143 + }, + { + "baselineNs": 26386.908749996113, + "candidateNs": 26313.095000000427 + }, + { + "baselineNs": 26017.047499999535, + "candidateNs": 27938.492500002212 + }, + { + "baselineNs": 25761.741249998522, + "candidateNs": 26929.848750000925 + }, + { + "baselineNs": 39596.02499999619, + "candidateNs": 46405.73250000216 + }, + { + "baselineNs": 25936.15750000026, + "candidateNs": 27629.483750001782 + }, + { + "baselineNs": 25706.197500003324, + "candidateNs": 26354.923750000125 + }, + { + "baselineNs": 26008.556249998946, + "candidateNs": 26361.861249997673 + }, + { + "baselineNs": 26437.25375000031, + "candidateNs": 26589.355000000978 + }, + { + "baselineNs": 25926.088750002236, + "candidateNs": 26419.9837499973 + }, + { + "baselineNs": 25817.496250001568, + "candidateNs": 26932.978750000984 + }, + { + "baselineNs": 25116.45750000298, + "candidateNs": 26287.72250000111 + }, + { + "baselineNs": 25342.172499999833, + "candidateNs": 27060.796250002564 + }, + { + "baselineNs": 25833.388749997543, + "candidateNs": 27034.658749998925 + }, + { + "baselineNs": 25495.30000000232, + "candidateNs": 26659.574999998767 + }, + { + "baselineNs": 48789.262499999495, + "candidateNs": 32122.56125000295 + }, + { + "baselineNs": 33407.353750003494, + "candidateNs": 30784.294999998565 + }, + { + "baselineNs": 30350.851250000233, + "candidateNs": 27722.23375000067 + }, + { + "baselineNs": 27022.648749998552, + "candidateNs": 28855.462499996065 + } + ] + }, + { + "mode": "legacy", + "name": "union list / 100 rows", + "count": 400, + "baselineNs": 59399.06499999779, + "candidateNs": 61791.40999999617, + "ratio": 1.0404216066506868, + "samples": [ + { + "baselineNs": 59116.85500000203, + "candidateNs": 62515.92999999957 + }, + { + "baselineNs": 58865.55750000298, + "candidateNs": 60039.55000000132 + }, + { + "baselineNs": 58877.779999993436, + "candidateNs": 59765.457499997865 + }, + { + "baselineNs": 58223.24249999838, + "candidateNs": 59975.4800000028 + }, + { + "baselineNs": 58348.580000001675, + "candidateNs": 77591.0500000009 + }, + { + "baselineNs": 62939.23250000262, + "candidateNs": 100672.39750000225 + }, + { + "baselineNs": 58878.632500000094, + "candidateNs": 61246.307499995964 + }, + { + "baselineNs": 59512.180000001536, + "candidateNs": 61124.87750000582 + }, + { + "baselineNs": 58598.324999993565, + "candidateNs": 60272.814999998445 + }, + { + "baselineNs": 59693.472500002834, + "candidateNs": 61340.6600000053 + }, + { + "baselineNs": 57712.29999999378, + "candidateNs": 68155.26499999578 + }, + { + "baselineNs": 63698.39250000041, + "candidateNs": 77430.3725000027 + }, + { + "baselineNs": 59530.34000000116, + "candidateNs": 61203.17499999146 + }, + { + "baselineNs": 58204.13250000456, + "candidateNs": 59800.90000000018 + }, + { + "baselineNs": 60236.39750000257, + "candidateNs": 100271.3649999987 + }, + { + "baselineNs": 61259.157499998764, + "candidateNs": 79952.18750000276 + }, + { + "baselineNs": 60877.13249999979, + "candidateNs": 61490.24249999456 + }, + { + "baselineNs": 61025.83999999297, + "candidateNs": 63492.60250000043 + }, + { + "baselineNs": 59332.89000000514, + "candidateNs": 60448.175000001356 + }, + { + "baselineNs": 58594.46750000642, + "candidateNs": 61261.80999999633 + }, + { + "baselineNs": 63254.30249999955, + "candidateNs": 60030.710000000916 + }, + { + "baselineNs": 58350.46000000147, + "candidateNs": 64582.337499996356 + }, + { + "baselineNs": 59399.06499999779, + "candidateNs": 63463.27250000286 + }, + { + "baselineNs": 60036.76999999697, + "candidateNs": 68643.98749999964 + }, + { + "baselineNs": 120632.62499999836, + "candidateNs": 90857.19499999868 + }, + { + "baselineNs": 58479.65250000016, + "candidateNs": 61791.40999999617 + }, + { + "baselineNs": 58318.09749999593, + "candidateNs": 60414.25999999774 + }, + { + "baselineNs": 64220.42749999491, + "candidateNs": 59995.04249999518 + }, + { + "baselineNs": 64329.00750000044, + "candidateNs": 73051.11749999924 + }, + { + "baselineNs": 59678.5699999964, + "candidateNs": 62254.18750000244 + }, + { + "baselineNs": 59117.7824999977, + "candidateNs": 62398.48499999425 + } + ] + }, + { + "mode": "legacy", + "name": "custom scalar list", + "count": 3200, + "baselineNs": 12087.76499999999, + "candidateNs": 12403.173437500072, + "ratio": 1.0245624323850053, + "samples": [ + { + "baselineNs": 15492.706562499734, + "candidateNs": 12150.574062499118 + }, + { + "baselineNs": 13419.469374999835, + "candidateNs": 11616.327187500701 + }, + { + "baselineNs": 12044.248437500755, + "candidateNs": 13205.070312499174 + }, + { + "baselineNs": 12595.587187499861, + "candidateNs": 14952.269374999789 + }, + { + "baselineNs": 12087.76499999999, + "candidateNs": 13202.840937500468 + }, + { + "baselineNs": 20496.047187500608, + "candidateNs": 12822.10593750051 + }, + { + "baselineNs": 11896.158749999586, + "candidateNs": 12144.07749999964 + }, + { + "baselineNs": 11386.041874999364, + "candidateNs": 12403.173437500072 + }, + { + "baselineNs": 12217.920312499475, + "candidateNs": 13024.287812500006 + }, + { + "baselineNs": 13157.611875000155, + "candidateNs": 13242.510000000037 + }, + { + "baselineNs": 11962.556249999352, + "candidateNs": 13420.82812499939 + }, + { + "baselineNs": 19287.888750000093, + "candidateNs": 14722.735312500392 + }, + { + "baselineNs": 12009.591875000751, + "candidateNs": 12803.777499999569 + }, + { + "baselineNs": 11567.35000000026, + "candidateNs": 13419.174999999088 + }, + { + "baselineNs": 11653.5003125, + "candidateNs": 12302.345624999587 + }, + { + "baselineNs": 11931.519687499303, + "candidateNs": 13880.450000000337 + }, + { + "baselineNs": 14575.13468749994, + "candidateNs": 12957.555625000625 + }, + { + "baselineNs": 14684.61062499955, + "candidateNs": 16807.021875000602 + }, + { + "baselineNs": 11908.485312500261, + "candidateNs": 11909.662499999738 + }, + { + "baselineNs": 11098.805000000311, + "candidateNs": 11723.952187500116 + }, + { + "baselineNs": 11320.217187500246, + "candidateNs": 12003.843749999989 + }, + { + "baselineNs": 11441.825312499532, + "candidateNs": 11834.674062499744 + }, + { + "baselineNs": 11237.504687500177, + "candidateNs": 10949.175624999725 + }, + { + "baselineNs": 18314.439687500228, + "candidateNs": 10835.604687499654 + }, + { + "baselineNs": 12703.866875000358, + "candidateNs": 11102.915937499349 + }, + { + "baselineNs": 12891.59937500017, + "candidateNs": 12007.09374999974 + }, + { + "baselineNs": 12331.835625000167, + "candidateNs": 11091.691562500047 + }, + { + "baselineNs": 11830.528749999305, + "candidateNs": 12121.115312500024 + }, + { + "baselineNs": 11538.504999999761, + "candidateNs": 11193.559062500071 + }, + { + "baselineNs": 13480.68812499946, + "candidateNs": 14366.099062500552 + }, + { + "baselineNs": 16184.739374999708, + "candidateNs": 14064.907812499996 + } + ] + }, + { + "mode": "legacy", + "name": "opaque JSON list", + "count": 102400, + "baselineNs": 328.04726562496, + "candidateNs": 336.50984375000803, + "ratio": 1.020969780190783, + "samples": [ + { + "baselineNs": 324.735927734352, + "candidateNs": 329.71359375000725 + }, + { + "baselineNs": 336.60650390626046, + "candidateNs": 342.5912499999839 + }, + { + "baselineNs": 314.9987695312362, + "candidateNs": 332.38759765627185 + }, + { + "baselineNs": 557.2195605468622, + "candidateNs": 360.7671093749687 + }, + { + "baselineNs": 324.28155273439785, + "candidateNs": 336.50984375000803 + }, + { + "baselineNs": 327.4914257812611, + "candidateNs": 333.01563476559437 + }, + { + "baselineNs": 322.705722656238, + "candidateNs": 329.52025390628137 + }, + { + "baselineNs": 331.5036035156283, + "candidateNs": 338.72045898437614 + }, + { + "baselineNs": 331.4998730468588, + "candidateNs": 334.5910742187641 + }, + { + "baselineNs": 319.0810937499933, + "candidateNs": 329.1513964843773 + }, + { + "baselineNs": 316.14038085937324, + "candidateNs": 502.15845703124984 + }, + { + "baselineNs": 316.65581054689085, + "candidateNs": 424.113007812501 + }, + { + "baselineNs": 315.3460058593893, + "candidateNs": 335.20375976564765 + }, + { + "baselineNs": 316.6645117187272, + "candidateNs": 334.64655273441224 + }, + { + "baselineNs": 333.38782226564945, + "candidateNs": 333.5953417968796 + }, + { + "baselineNs": 331.32425781246866, + "candidateNs": 331.85974609374114 + }, + { + "baselineNs": 357.2394433593474, + "candidateNs": 346.84871093745073 + }, + { + "baselineNs": 532.831572265664, + "candidateNs": 353.44653320315444 + }, + { + "baselineNs": 366.81848632817093, + "candidateNs": 342.3475292969158 + }, + { + "baselineNs": 327.51842773436124, + "candidateNs": 345.79515624997725 + }, + { + "baselineNs": 327.4145214844282, + "candidateNs": 334.2803320312271 + }, + { + "baselineNs": 340.21694335933717, + "candidateNs": 337.5934277344328 + }, + { + "baselineNs": 322.7479882812645, + "candidateNs": 339.759238281232 + }, + { + "baselineNs": 333.37294921878424, + "candidateNs": 329.0458300781296 + }, + { + "baselineNs": 314.94995117185454, + "candidateNs": 560.8263769531163 + }, + { + "baselineNs": 346.2356347656481, + "candidateNs": 374.40430664062774 + }, + { + "baselineNs": 365.5280664062843, + "candidateNs": 365.74682617185766 + }, + { + "baselineNs": 334.70857421875166, + "candidateNs": 352.81165039059204 + }, + { + "baselineNs": 331.95983398442763, + "candidateNs": 334.8490820312833 + }, + { + "baselineNs": 320.39745117188545, + "candidateNs": 334.23874999996883 + }, + { + "baselineNs": 328.04726562496, + "candidateNs": 332.25609374994747 + } + ] + }, + { + "mode": "legacy", + "name": "recursive inputs", + "count": 400, + "baselineNs": 29874.46249999266, + "candidateNs": 28628.48250000752, + "ratio": 0.9556535676489639, + "samples": [ + { + "baselineNs": 43298.909999994066, + "candidateNs": 30696.49249999202 + }, + { + "baselineNs": 32629.370000013296, + "candidateNs": 36366.13249998845 + }, + { + "baselineNs": 26842.682499991497, + "candidateNs": 28998.78500000341 + }, + { + "baselineNs": 27812.114999996993, + "candidateNs": 29557.06499998996 + }, + { + "baselineNs": 28465.875000001684, + "candidateNs": 27203.51500000106 + }, + { + "baselineNs": 27174.135000004753, + "candidateNs": 27522.97000000908 + }, + { + "baselineNs": 27206.145000000106, + "candidateNs": 26149.01999999347 + }, + { + "baselineNs": 27872.527499985154, + "candidateNs": 26161.2950000017 + }, + { + "baselineNs": 26729.220000015626, + "candidateNs": 26392.83250000517 + }, + { + "baselineNs": 27393.92499999667, + "candidateNs": 25777.04499999527 + }, + { + "baselineNs": 29694.64750000043, + "candidateNs": 27851.940000000464 + }, + { + "baselineNs": 29874.46249999266, + "candidateNs": 27303.95500000668 + }, + { + "baselineNs": 30032.034999985626, + "candidateNs": 28059.807499994346 + }, + { + "baselineNs": 30815.817499988043, + "candidateNs": 27975.624999999123 + }, + { + "baselineNs": 30111.812499999356, + "candidateNs": 27940.45750000805 + }, + { + "baselineNs": 29629.225000007864, + "candidateNs": 29786.872500008027 + }, + { + "baselineNs": 29806.334999993855, + "candidateNs": 29954.214999997934 + }, + { + "baselineNs": 29175.367499992717, + "candidateNs": 27698.824999988574 + }, + { + "baselineNs": 28400.302499994723, + "candidateNs": 47229.31250000329 + }, + { + "baselineNs": 51988.485000001674, + "candidateNs": 51108.422500001325 + }, + { + "baselineNs": 30336.837499999092, + "candidateNs": 28975.01250001369 + }, + { + "baselineNs": 34320.540000007895, + "candidateNs": 28906.2075000038 + }, + { + "baselineNs": 30342.722500008676, + "candidateNs": 27856.272499993793 + }, + { + "baselineNs": 35724.369999988994, + "candidateNs": 31299.582500014367 + }, + { + "baselineNs": 30217.937500001426, + "candidateNs": 30189.80749999173 + }, + { + "baselineNs": 30379.31750001008, + "candidateNs": 29142.9799999969 + }, + { + "baselineNs": 28810.452500001706, + "candidateNs": 34129.22999999864 + }, + { + "baselineNs": 31016.997499991703, + "candidateNs": 30127.31500000882 + }, + { + "baselineNs": 29400.392499992446, + "candidateNs": 27537.872499997316 + }, + { + "baselineNs": 32587.31500000067, + "candidateNs": 28425.44999999518 + }, + { + "baselineNs": 29936.180000004242, + "candidateNs": 28628.48250000752 + } + ] + } + ] +} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/results/size.json b/packages/rescript-relay/benchmarks/rescript-runtime/results/size.json new file mode 100644 index 00000000..5a15fce6 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/results/size.json @@ -0,0 +1,26 @@ +{ + "esbuild": "0.25.12", + "node": "v24.16.0", + "results": { + "baselineEsm": { + "minified": 5578, + "gzip": 2238, + "brotli": 2032 + }, + "candidateEsm": { + "minified": 6328, + "gzip": 2638, + "brotli": 2352 + }, + "baselineCjs": { + "minified": 5786, + "gzip": 2330, + "brotli": 2108 + }, + "candidateCjs": { + "minified": 6426, + "gzip": 2689, + "brotli": 2387 + } + } +} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/results/summary.json b/packages/rescript-relay/benchmarks/rescript-runtime/results/summary.json new file mode 100644 index 00000000..e1d6b4d1 --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/results/summary.json @@ -0,0 +1,512 @@ +[ + { + "fixtureVersion": 3, + "node": "v24.16.0", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 31, + "targetSampleMs": 20, + "initialLoad": [ + 20.17, + 20.63, + 18.13 + ], + "finalLoad": [ + 22.07, + 21.04, + 18.36 + ], + "sha256": { + "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", + "candidate": "efdf597c559c9b77f3d07ec1c3887eb37708d373d4f820250af2436ce39a08ea", + "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" + }, + "results": [ + { + "mode": "prepared", + "name": "small fragment", + "count": 204800, + "baselineNs": 121.7566015624999, + "candidateNs": 104.14479492187489, + "ratio": 0.8349709257422858 + }, + { + "mode": "prepared", + "name": "unchanged object", + "count": 409600, + "baselineNs": 82.96166992187604, + "candidateNs": 66.24224853515659, + "ratio": 0.7671853743271453 + }, + { + "mode": "prepared", + "name": "nullable query", + "count": 204800, + "baselineNs": 171.84698242187488, + "candidateNs": 142.77499511718972, + "ratio": 0.8231401354539566 + }, + { + "mode": "prepared", + "name": "connection / 100 rows", + "count": 800, + "baselineNs": 28019.937499999516, + "candidateNs": 23009.4787500002, + "ratio": 0.7902347823769934 + }, + { + "mode": "prepared", + "name": "plural fragment / 100 rows", + "count": 1600, + "baselineNs": 21462.98687500007, + "candidateNs": 18526.618125000598, + "ratio": 0.8794271797765583 + }, + { + "mode": "prepared", + "name": "union list / 100 rows", + "count": 1600, + "baselineNs": 29198.695625000255, + "candidateNs": 22342.16062499968, + "ratio": 0.7778951643576937 + }, + { + "mode": "prepared", + "name": "custom scalar list", + "count": 1600, + "baselineNs": 14437.52687500023, + "candidateNs": 13762.3318750002, + "ratio": 0.981652431743633 + }, + { + "mode": "prepared", + "name": "opaque JSON list", + "count": 51200, + "baselineNs": 486.72876953123273, + "candidateNs": 552.9230273437591, + "ratio": 1.139742761268076 + }, + { + "mode": "prepared", + "name": "recursive inputs", + "count": 1600, + "baselineNs": 17189.039375000448, + "candidateNs": 15425.186874999781, + "ratio": 0.8949551895398633 + }, + { + "mode": "legacy", + "name": "small fragment", + "count": 102400, + "baselineNs": 273.1039941406266, + "candidateNs": 272.25033203123417, + "ratio": 1.0088202936374087 + }, + { + "mode": "legacy", + "name": "unchanged object", + "count": 204800, + "baselineNs": 119.56970703124625, + "candidateNs": 118.65616210936736, + "ratio": 1.0026406056022323 + }, + { + "mode": "legacy", + "name": "nullable query", + "count": 102400, + "baselineNs": 410.2593359375106, + "candidateNs": 430.05709960937105, + "ratio": 1.0382845115265 + }, + { + "mode": "legacy", + "name": "connection / 100 rows", + "count": 400, + "baselineNs": 62852.29750000326, + "candidateNs": 60790.202500002124, + "ratio": 0.9704859580920145 + }, + { + "mode": "legacy", + "name": "plural fragment / 100 rows", + "count": 800, + "baselineNs": 29465.092499999628, + "candidateNs": 28555.748750000017, + "ratio": 0.9673666667809608 + }, + { + "mode": "legacy", + "name": "union list / 100 rows", + "count": 400, + "baselineNs": 83758.23749999654, + "candidateNs": 82353.2350000005, + "ratio": 1.0079768791213282 + }, + { + "mode": "legacy", + "name": "custom scalar list", + "count": 1600, + "baselineNs": 12798.784999999953, + "candidateNs": 15587.23687499878, + "ratio": 1.0955781158925082 + }, + { + "mode": "legacy", + "name": "opaque JSON list", + "count": 102400, + "baselineNs": 349.20759765618925, + "candidateNs": 354.2060253906243, + "ratio": 1.0446409110718158 + }, + { + "mode": "legacy", + "name": "recursive inputs", + "count": 800, + "baselineNs": 30331.65625000038, + "candidateNs": 31331.545000002734, + "ratio": 1.0406183435481944 + } + ], + "run": 1 + }, + { + "fixtureVersion": 3, + "node": "v24.16.0", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 31, + "targetSampleMs": 20, + "initialLoad": [ + 22.07, + 21.04, + 18.36 + ], + "finalLoad": [ + 28.26, + 22.65, + 18.99 + ], + "sha256": { + "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", + "candidate": "efdf597c559c9b77f3d07ec1c3887eb37708d373d4f820250af2436ce39a08ea", + "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" + }, + "results": [ + { + "mode": "prepared", + "name": "small fragment", + "count": 204800, + "baselineNs": 104.14513671874958, + "candidateNs": 95.33473632812428, + "ratio": 0.9108305326447267 + }, + { + "mode": "prepared", + "name": "unchanged object", + "count": 819200, + "baselineNs": 57.97080200195315, + "candidateNs": 44.429227294921496, + "ratio": 0.7691966977713872 + }, + { + "mode": "prepared", + "name": "nullable query", + "count": 204800, + "baselineNs": 150.56852539062413, + "candidateNs": 120.17709960937319, + "ratio": 0.8092346328869575 + }, + { + "mode": "prepared", + "name": "connection / 100 rows", + "count": 1600, + "baselineNs": 21812.62812499995, + "candidateNs": 17182.614375000183, + "ratio": 0.7829377120803431 + }, + { + "mode": "prepared", + "name": "plural fragment / 100 rows", + "count": 1600, + "baselineNs": 17919.695624999575, + "candidateNs": 13700.545625000586, + "ratio": 0.8055782319164054 + }, + { + "mode": "prepared", + "name": "union list / 100 rows", + "count": 1600, + "baselineNs": 19935.49874999985, + "candidateNs": 15270.431250000911, + "ratio": 0.7984162928963018 + }, + { + "mode": "prepared", + "name": "custom scalar list", + "count": 1600, + "baselineNs": 15037.666250000257, + "candidateNs": 15093.140000000178, + "ratio": 0.9916541786235471 + }, + { + "mode": "prepared", + "name": "opaque JSON list", + "count": 51200, + "baselineNs": 478.9705468749972, + "candidateNs": 591.4377929687475, + "ratio": 1.1668516517895595 + }, + { + "mode": "prepared", + "name": "recursive inputs", + "count": 1600, + "baselineNs": 21305.57562499917, + "candidateNs": 20676.862499999515, + "ratio": 0.9774872831559546 + }, + { + "mode": "legacy", + "name": "small fragment", + "count": 102400, + "baselineNs": 278.36558593747895, + "candidateNs": 265.05880859375, + "ratio": 0.9637947252024088 + }, + { + "mode": "legacy", + "name": "unchanged object", + "count": 204800, + "baselineNs": 133.6500732421797, + "candidateNs": 117.47829589843661, + "ratio": 0.9017787405511776 + }, + { + "mode": "legacy", + "name": "nullable query", + "count": 51200, + "baselineNs": 455.09160156250056, + "candidateNs": 443.55710937502124, + "ratio": 0.9706720376398672 + }, + { + "mode": "legacy", + "name": "connection / 100 rows", + "count": 400, + "baselineNs": 61725.01750000266, + "candidateNs": 60333.2600000067, + "ratio": 0.9813983111234094 + }, + { + "mode": "legacy", + "name": "plural fragment / 100 rows", + "count": 800, + "baselineNs": 28664.328750001005, + "candidateNs": 26220.58375000051, + "ratio": 0.9284585537800738 + }, + { + "mode": "legacy", + "name": "union list / 100 rows", + "count": 400, + "baselineNs": 62901.56499999285, + "candidateNs": 63541.09750000134, + "ratio": 1.0522648822420053 + }, + { + "mode": "legacy", + "name": "custom scalar list", + "count": 3200, + "baselineNs": 11616.421562499681, + "candidateNs": 12326.83624999936, + "ratio": 1.05460484430652 + }, + { + "mode": "legacy", + "name": "opaque JSON list", + "count": 102400, + "baselineNs": 336.435205078125, + "candidateNs": 341.56414062497475, + "ratio": 1.0231712783309246 + }, + { + "mode": "legacy", + "name": "recursive inputs", + "count": 800, + "baselineNs": 28766.95875000223, + "candidateNs": 30134.682500001873, + "ratio": 1.0391593275107527 + } + ], + "run": 2 + }, + { + "fixtureVersion": 3, + "node": "v24.16.0", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 31, + "targetSampleMs": 20, + "initialLoad": [ + 20.68, + 21.39, + 18.74 + ], + "finalLoad": [ + 19.18, + 20.96, + 18.69 + ], + "sha256": { + "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", + "candidate": "efdf597c559c9b77f3d07ec1c3887eb37708d373d4f820250af2436ce39a08ea", + "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" + }, + "results": [ + { + "mode": "prepared", + "name": "small fragment", + "count": 409600, + "baselineNs": 102.4374340820311, + "candidateNs": 91.70031738281237, + "ratio": 0.9006024123311214 + }, + { + "mode": "prepared", + "name": "unchanged object", + "count": 409600, + "baselineNs": 55.89947509765713, + "candidateNs": 44.29194091796873, + "ratio": 0.7933846994786131 + }, + { + "mode": "prepared", + "name": "nullable query", + "count": 204800, + "baselineNs": 148.93603515625298, + "candidateNs": 123.57809570312739, + "ratio": 0.8220193300149227 + }, + { + "mode": "prepared", + "name": "connection / 100 rows", + "count": 1600, + "baselineNs": 21940.737499999726, + "candidateNs": 18028.042500000083, + "ratio": 0.8210054435040013 + }, + { + "mode": "prepared", + "name": "plural fragment / 100 rows", + "count": 1600, + "baselineNs": 15024.559375000308, + "candidateNs": 12962.843749999138, + "ratio": 0.8388993027599011 + }, + { + "mode": "prepared", + "name": "union list / 100 rows", + "count": 1600, + "baselineNs": 18634.26312499996, + "candidateNs": 14601.722500000276, + "ratio": 0.8197016737223956 + }, + { + "mode": "prepared", + "name": "custom scalar list", + "count": 3200, + "baselineNs": 11663.735624999845, + "candidateNs": 11913.714062499706, + "ratio": 1.02246230509656 + }, + { + "mode": "prepared", + "name": "opaque JSON list", + "count": 51200, + "baselineNs": 441.32806640622135, + "candidateNs": 538.5150781249947, + "ratio": 1.2004831145919181 + }, + { + "mode": "prepared", + "name": "recursive inputs", + "count": 1600, + "baselineNs": 16857.66187499894, + "candidateNs": 14194.308749999891, + "ratio": 0.8569818680573524 + }, + { + "mode": "legacy", + "name": "small fragment", + "count": 102400, + "baselineNs": 263.53763671874475, + "candidateNs": 255.13298828126807, + "ratio": 0.9817418609062459 + }, + { + "mode": "legacy", + "name": "unchanged object", + "count": 102400, + "baselineNs": 111.38375976564419, + "candidateNs": 110.24087890621814, + "ratio": 0.9926745976948665 + }, + { + "mode": "legacy", + "name": "nullable query", + "count": 102400, + "baselineNs": 446.55356445311156, + "candidateNs": 429.20505859374464, + "ratio": 0.9638199985851299 + }, + { + "mode": "legacy", + "name": "connection / 100 rows", + "count": 400, + "baselineNs": 64871.20750000031, + "candidateNs": 65180.14249999396, + "ratio": 1.0035241512219875 + }, + { + "mode": "legacy", + "name": "plural fragment / 100 rows", + "count": 800, + "baselineNs": 26386.908749996113, + "candidateNs": 27629.483750001782, + "ratio": 1.0432064553896991 + }, + { + "mode": "legacy", + "name": "union list / 100 rows", + "count": 400, + "baselineNs": 59399.06499999779, + "candidateNs": 61791.40999999617, + "ratio": 1.0404216066506868 + }, + { + "mode": "legacy", + "name": "custom scalar list", + "count": 3200, + "baselineNs": 12087.76499999999, + "candidateNs": 12403.173437500072, + "ratio": 1.0245624323850053 + }, + { + "mode": "legacy", + "name": "opaque JSON list", + "count": 102400, + "baselineNs": 328.04726562496, + "candidateNs": 336.50984375000803, + "ratio": 1.020969780190783 + }, + { + "mode": "legacy", + "name": "recursive inputs", + "count": 400, + "baselineNs": 29874.46249999266, + "candidateNs": 28628.48250000752, + "ratio": 0.9556535676489639 + } + ], + "run": 3 + } +] diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/size.js b/packages/rescript-relay/benchmarks/rescript-runtime/size.js new file mode 100644 index 00000000..2f5dff1e --- /dev/null +++ b/packages/rescript-relay/benchmarks/rescript-runtime/size.js @@ -0,0 +1,23 @@ +const fs = require("fs"); +const path = require("path"); +const zlib = require("zlib"); +const esbuild = require("esbuild"); +const {buildConversionModules} = require("../../scripts/build-conversion-modules"); +async function measure() { + const output = path.join(__dirname, "output"); + buildConversionModules(path.join(output, "baseline")); + const results = {}; + for (const [name, entry] of [ + ["baselineEsm", path.join(output, "baseline/utils.mjs")], + ["candidateEsm", path.join(output, "utils.mjs")], + ["baselineCjs", path.resolve(__dirname, "../../src/utils.js")], + ["candidateCjs", path.join(output, "utils.cjs")], + ]) { + const result = await esbuild.build({entryPoints: [entry], bundle: true, minify: true, format: "esm", write: false}); + const bytes = result.outputFiles[0].contents; + results[name] = {minified: bytes.length, gzip: zlib.gzipSync(bytes, {level: 9}).length, brotli: zlib.brotliCompressSync(bytes).length}; + } + fs.writeFileSync(path.join(output, "size.json"), JSON.stringify({esbuild: esbuild.version, node: process.version, results}, null, 2) + "\n"); + console.table(results); +} +measure().catch(error => {console.error(error); process.exitCode = 1;}); diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res index 3371d72c..30a32bf9 100644 --- a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res +++ b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res @@ -25,9 +25,9 @@ type rec node = {children: dict, instructions: dict} fail("Invalid conversion plan: expected version 2 and roots") } let roots = create() - let fields1 = keys(rawRoots) - for index1 in 0 to Array.length(fields1) - 1 { - let name = unsafeAt(fields1, index1) + let rootNames = keys(rawRoots) + for rootIndex in 0 to Array.length(rootNames) - 1 { + let name = unsafeAt(rootNames, rootIndex) let entries: value = get(rawRoots, name) if !isArray(entries) { fail("Invalid conversion root: " ++ name) @@ -59,9 +59,9 @@ type rec node = {children: dict, instructions: dict} target := child } } - let fields2 = keys(entry) - for index2 in 0 to Array.length(fields2) - 1 { - let key = unsafeAt(fields2, index2) + let instructionKeys = keys(entry) + for keyIndex in 0 to Array.length(instructionKeys) - 1 { + let key = unsafeAt(instructionKeys, keyIndex) switch key { | "path" => () | "list" | "scalar" | "union" | "reference" | "opaque" | "fragments" => @@ -80,27 +80,6 @@ type rec node = {children: dict, instructions: dict} } roots } - let arrayOf = (convert: converter): converter => - values => { - let result = ref(jsUndefined) - for i in 0 to length(values) - 1 { - if hasIndex(i, values) { - let value = at(values, i) - let next = convert(value) - if next !== value { - if result.contents === jsUndefined { - result := slice(values) - } - put(result.contents, i, next) - } - } - } - if result.contents === jsUndefined { - values - } else { - result.contents - } - } ) let prepareConversion = ( @@ -122,6 +101,27 @@ let prepareConversion = ( fail("Missing conversion root: " ++ rootName) } let converters: dict = create() + let arrayOf = (convert: converter): converter => + values => { + let result = ref(jsUndefined) + for i in 0 to length(values) - 1 { + if hasIndex(i, values) { + let value = at(values, i) + let next = convert(value) + if next !== value { + if result.contents === jsUndefined { + result := slice(values) + } + put(result.contents, i, next) + } + } + } + if result.contents === jsUndefined { + values + } else { + result.contents + } + } let nullableOnly: converter = value => if isNullable(value) { nullable @@ -192,16 +192,15 @@ let prepareConversion = ( if Array.length(allOperations) > 1 { fail("Conflicting conversion operations: " ++ Array.join(allOperations, ", ")) } - let fields4 = operations - for index4 in 0 to Array.length(fields4) - 1 { - let key = unsafeAt(fields4, index4) + for operationIndex in 0 to Array.length(operations) - 1 { + let key = unsafeAt(operations, operationIndex) if typeOf(get(ops, key)) !== "string" { fail("Invalid conversion " ++ key) } } - let fields5 = ["opaque", "fragments"] - for index5 in 0 to Array.length(fields5) - 1 { - let key = unsafeAt(fields5, index5) + let flags = ["opaque", "fragments"] + for flagIndex in 0 to Array.length(flags) - 1 { + let key = unsafeAt(flags, flagIndex) if hasOwn(ops, key) && get(ops, key) !== cast(true) { fail("Invalid conversion " ++ key) } @@ -244,9 +243,8 @@ let prepareConversion = ( } } else { let children: dict = create() - let fields6 = names - for index6 in 0 to Array.length(fields6) - 1 { - let name = unsafeAt(fields6, index6) + for childIndex in 0 to Array.length(names) - 1 { + let name = unsafeAt(names, childIndex) set(children, name, compile(get(node.children, name))) } let union: value = get(ops, "union") @@ -280,9 +278,9 @@ let prepareConversion = ( } convert.contents } - let fields7 = keys(roots) - for index7 in 0 to Array.length(fields7) - 1 { - let name = unsafeAt(fields7, index7) + let rootNames = keys(roots) + for rootIndex in 0 to Array.length(rootNames) - 1 { + let name = unsafeAt(rootNames, rootIndex) set(converters, name, compile(get(roots, name))) } let convert: converter = get(converters, rootName) diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res index 0518bc80..cb719a33 100644 --- a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res +++ b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res @@ -1,4 +1,4 @@ -// Dynamic Relay values include jsNull, jsUndefined, custom scalar instances and +// Dynamic Relay values include null, undefined, custom scalar instances and // ReScript option markers. Keep unchecked property access at this FFI boundary. type value type converter = value => value From c037d41b82ed2e6e92f803d01a2b3b1394724591 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 11:40:03 +0200 Subject: [PATCH 12/23] Specialize generic records and opaque lists in prepared conversion --- .../__tests__/utils-prepared-tests.js | 70 +++++++++++++++++++ .../scripts/test-conversion-mutations.js | 27 ++++++- .../rescript-relay/src/prepareConversion.js | 34 ++++++++- 3 files changed, 128 insertions(+), 3 deletions(-) diff --git a/packages/rescript-relay/__tests__/utils-prepared-tests.js b/packages/rescript-relay/__tests__/utils-prepared-tests.js index 4877d523..c70b8034 100644 --- a/packages/rescript-relay/__tests__/utils-prepared-tests.js +++ b/packages/rescript-relay/__tests__/utils-prepared-tests.js @@ -667,3 +667,73 @@ describe.each([null, undefined])( ); }, ); + +describe.each([undefined, null])("specialized traversal (%s)", (nullable) => { + test("opaque lists normalize only present nullish elements and retain nested identities", () => { + const cyclic = { value: null }; + cyclic.self = cyclic; + const nested = [null, undefined]; + const marker = { BS_PRIVATE_NESTED_SOME_NONE: 0 }; + const values = [null, , undefined, cyclic, nested, marker, 0, false, "", null, undefined]; + const input = freeze({ values }); + const convert = prepare(object({ values: list(opaque) }), {}, nullable); + const output = convert(input); + expect(output).toStrictEqual({ + values: [nullable, , nullable, cyclic, nested, marker, 0, false, "", nullable, nullable], + }); + expect(output).not.toBe(input); + expect(output.values).not.toBe(values); + expect(1 in output.values).toBe(false); + for (const index of [3, 4, 5]) expect(output.values[index]).toBe(values[index]); + expect(values[0]).toBe(null); + expect(values[2]).toBeUndefined(); + const unchanged = freeze({ values: [nullable, , cyclic, nested, marker] }); + expect(convert(unchanged)).toBe(unchanged); + const empty = freeze({ values: [] }); + expect(convert(empty)).toBe(empty); + }); + + test("opaque sparse lists preserve inherited array elements when copying", () => { + const inherited = freeze({ value: null }); + const prototype = Object.create(Array.prototype); + prototype[1] = inherited; + const values = [null, , undefined]; + Object.setPrototypeOf(values, prototype); + Object.freeze(values); + const output = prepare(list(opaque), {}, nullable)(values); + expect(output).toStrictEqual([nullable, inherited, nullable]); + expect(output[1]).toBe(inherited); + expect(Object.prototype.hasOwnProperty.call(values, 1)).toBe(false); + expect(values[0]).toBe(null); + expect(values[2]).toBeUndefined(); + }); + + test("generic objects skip inherited fields and metadata while preserving own-key order", () => { + const metadata = {}; + metadata.self = metadata; + const input = Object.assign(Object.create({ inherited: { value: null } }), { + "2": null, + z: undefined, + __metadata: metadata, + stable: { value: 1 }, + a: null, + }); + Object.defineProperty(input, "__proto__", { + value: { value: null, other: undefined }, + enumerable: true, + }); + freeze(input); + const output = prepare(object(), {}, nullable)(input); + expect(Object.keys(output)).toEqual(Object.keys(input)); + expect(output).not.toHaveProperty("inherited"); + expect(output.__metadata).toBe(metadata); + expect(output.stable).toBe(input.stable); + expect(Object.getPrototypeOf(output)).toBe(Object.prototype); + expect(Object.prototype.hasOwnProperty.call(output, "__proto__")).toBe(true); + // Double-underscore keys are opaque metadata, including __proto__. + expect(output.__proto__).toBe(input.__proto__); + expect(output["2"]).toBe(nullable); + expect(output.z).toBe(nullable); + expect(output.a).toBe(nullable); + }); +}); diff --git a/packages/rescript-relay/scripts/test-conversion-mutations.js b/packages/rescript-relay/scripts/test-conversion-mutations.js index aa5f89da..0036c9a9 100644 --- a/packages/rescript-relay/scripts/test-conversion-mutations.js +++ b/packages/rescript-relay/scripts/test-conversion-mutations.js @@ -32,7 +32,32 @@ const faults = [ "isOption(value) ? value : convert(value)", "isOption(value) ? convert(value) : convert(value)", ], - ["sparse lists", "if (!(i in values)) continue;", ""], + ["opaque sparse lists", "if (!(i in values)) continue;", ""], + [ + "callback sparse lists", + "for (let i = 0; i < values.length; i++) {\n if (!(i in values)) continue;", + "for (let i = 0; i < values.length; i++) {", + ], + [ + "opaque-list null handling", + "const next = value == null ? nullable : value;", + "const next = value;", + ], + [ + "opaque-list boundary", + "const next = value == null ? nullable : value;", + "const next = any(value);", + ], + [ + "generic object mutation", + "const next = any(original);\n if (next !== original) {\n if (result === undefined) result = { ...value };", + "const next = any(original);\n if (next !== original) {\n if (result === undefined) result = value;", + ], + [ + "generic metadata boundary", + "function plainObject(value) {\n let result;\n for (const key in value) {\n if (!hasOwn(value, key) || isMetadata(key)) continue;", + "function plainObject(value) {\n let result;\n for (const key in value) {\n if (!hasOwn(value, key)) continue;", + ], [ "callback count", "const next = convert(value);", diff --git a/packages/rescript-relay/src/prepareConversion.js b/packages/rescript-relay/src/prepareConversion.js index a32035ca..cb2a89e9 100644 --- a/packages/rescript-relay/src/prepareConversion.js +++ b/packages/rescript-relay/src/prepareConversion.js @@ -74,7 +74,23 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { return (value) => value == null ? nullable : isOption(value) ? value : convert(value); } + // Opaque list elements only normalize nullability; no callback dispatch or + // traversal is needed, even when an element is itself an object or array. + function nullableArray(values) { + let result; + for (let i = 0; i < values.length; i++) { + if (!(i in values)) continue; + const value = values[i]; + const next = value == null ? nullable : value; + if (next !== value) { + if (result === undefined) result = values.slice(); + result[i] = next; + } + } + return result === undefined ? values : result; + } function arrayOf(convert) { + if (convert === nullableOnly) return nullableArray; return (values) => { let result; for (let i = 0; i < values.length; i++) { @@ -89,7 +105,7 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { return result === undefined ? values : result; }; } - const anyArray = arrayOf((value) => any(value)); + const anyArray = arrayOf(any); function any(value) { if (value == null) return nullable; if (typeof value !== "object" || isOption(value)) return value; @@ -115,7 +131,21 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { return result === undefined ? value : result; }; } - const plainObject = record(Object.create(null), false); + // Generic objects have no field instructions. Avoid a dictionary lookup for + // every selected field while retaining property order and lazy copying. + function plainObject(value) { + let result; + for (const key in value) { + if (!hasOwn(value, key) || isMetadata(key)) continue; + const original = value[key]; + const next = any(original); + if (next !== original) { + if (result === undefined) result = { ...value }; + result[key] = next; + } + } + return result === undefined ? value : result; + } function callback(name) { if ( !callbacks || From e1b12c732ea258f338defeed058061e8f78609e4 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 11:59:45 +0200 Subject: [PATCH 13/23] Validate JavaScript fast paths and record paired performance measurements --- packages/rescript-relay/benchmarks/README.md | 29 +- packages/rescript-relay/benchmarks/RESULTS.md | 51 +- packages/rescript-relay/benchmarks/SIZE.md | 15 + .../benchmarks/compare-conversion.js | 110 ++ .../rescript-relay/benchmarks/conversion.js | 30 +- .../benchmarks/rescript-runtime/README.md | 6 +- .../js-specialization/artifact-size.json | 792 +++++++++++ .../js-specialization/paired-final.json | 1237 +++++++++++++++++ .../js-specialization/paired-summary.json | 210 +++ .../js-specialization/runtime-size-esm.json | 15 + .../js-specialization/runtime-size.json | 15 + .../js-specialization/standalone-after.json | 670 +++++++++ .../js-specialization/standalone-before.json | 670 +++++++++ .../rescript-relay/src/prepareConversion.js | 7 +- 14 files changed, 3845 insertions(+), 12 deletions(-) create mode 100644 packages/rescript-relay/benchmarks/compare-conversion.js create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/artifact-size.json create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/paired-final.json create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/paired-summary.json create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/runtime-size-esm.json create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/runtime-size.json create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/standalone-after.json create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/standalone-before.json diff --git a/packages/rescript-relay/benchmarks/README.md b/packages/rescript-relay/benchmarks/README.md index 12d0072f..a1738ca5 100644 --- a/packages/rescript-relay/benchmarks/README.md +++ b/packages/rescript-relay/benchmarks/README.md @@ -23,6 +23,26 @@ yarn bench:conversion --implementation /tmp/utils-before.cjs --output /tmp/conve yarn bench:conversion:prepared --compare /tmp/conversion-before.json --output /tmp/conversion-after.json ``` +For paired comparisons of equivalent prepared runtimes, extract both JavaScript +modules from the baseline revision and alternate their execution within each +sample. For example, to reproduce the latest JavaScript optimization: + +```sh +mkdir -p /tmp/relay-conversion-before +git show 3de062b:packages/rescript-relay/src/utils.js > /tmp/relay-conversion-before/utils.js +git show 3de062b:packages/rescript-relay/src/prepareConversion.js > /tmp/relay-conversion-before/prepareConversion.js +node benchmarks/compare-conversion.js --baseline /tmp/relay-conversion-before/utils.js --output /tmp/paired-conversion.json +``` + +The paired harness checks complete output equality and input immutability, warms +both implementations, and collects 31 pairs with alternating execution order. +Reports retain every pair, source hashes, and host load. `--candidate ` can +select another runtime; `--legacy` compares the legacy API instead. It defaults +to prepared conversion and requires equivalent behavior from both implementations. +Historical runtimes with intentionally different semantics need the original +fixture-based harness above. Pairing reduces temporal bias, but does not remove +JIT or shared-host noise; also check separate processes and repeat measurements. + Run those commands sequentially on an otherwise idle machine, with the same Node version. Repeat in reversed order to check for warmup, CPU frequency, or load bias. `--samples` (default 15) and `--duration` (default 40 ms per sample) control @@ -40,9 +60,16 @@ memory. It excludes temporary objects that are already unreachable. CI uploads this report and conversion coverage; timings are informational, while correctness and coverage failures block CI. -For CPU and GC investigation: +For CPU and GC investigation, `--cpu-time` records CPU nanoseconds alongside +elapsed time and retains individual samples in the JSON report. It uses the +current thread's CPU time when Node provides it; older Node versions fall back to +process CPU time, including worker threads. The report identifies which was used. +CPU time helps diagnose scheduling waits but still varies with frequency, +contention, GC and JIT behavior. It does not replace elapsed-time measurements. + ```sh +node benchmarks/conversion.js --prepared --cpu-time --output /tmp/conversion-cpu.json node --cpu-prof --cpu-prof-dir=/tmp benchmarks/conversion.js node --trace-gc benchmarks/conversion.js > /tmp/conversion-gc.log ``` diff --git a/packages/rescript-relay/benchmarks/RESULTS.md b/packages/rescript-relay/benchmarks/RESULTS.md index eb7000db..359f46b8 100644 --- a/packages/rescript-relay/benchmarks/RESULTS.md +++ b/packages/rescript-relay/benchmarks/RESULTS.md @@ -25,4 +25,53 @@ Sources: - `first-pass`: `3770abc`, extracted `src/utils.js`. - `legacy` / `prepared`: the prepared runtime at `e856b90`, before the later bundle-size optimization. -Use the current fixture-version 2 reports named `forward-*.json` and `reverse-*.json` for comparisons. Earlier `baseline.json`, `optimized.json`, and `pr-673.json` are historical fixture-version 1 measurements and must not be mixed with them. See [the benchmark guide](README.md) for commands. +For the historical table above, use the fixture-version 2 reports named `forward-*.json` and `reverse-*.json` for comparisons. Earlier `baseline.json`, `optimized.json`, and `pr-673.json` are historical fixture-version 1 measurements and must not be mixed with them. See [the benchmark guide](README.md) for commands. + +## Further JavaScript specialization (fixture version 3) + +The JavaScript runtime now has two narrow fast paths: generic records bypass +empty instruction-dictionary lookups, and opaque lists normalize nullability +without per-element converter calls. The list implementation is selected while +preparing the plan; ordinary list conversion is unchanged. Sparse-array handling, +metadata boundaries, callback ordering, lazy copying and output identities retain +their existing semantics. More aggressive wrapper/inlining changes were not kept. + +The baseline is `3de062b`, immediately before this optimization. Two final paired +runs used Node 24.16.0, 31 alternating pairs per case, and CPU affinity 7 on the +same AMD host. Negative values mean less conversion time; these are ranges of +median per-pair time changes, not application latency gains: + +| Case | Paired conversion-time change | +| --- | ---: | +| Small fragment | -9.0% to -8.9% | +| Unchanged object | -15.0% to -14.8% | +| Nullable query | -19.1% to -18.9% | +| Connection, 100 rows | -20.2% to -19.8% | +| Plural fragment, 100 rows | -15.0% to -14.5% | +| Union list, 100 rows | -25.1% to -17.7% | +| Custom scalar list | -2.3% to -0.1% (approximately unchanged) | +| Opaque JSON list | -66.8% to -66.3% (about 3× throughput) | +| Recursive inputs | -11.1% to -5.7% | + +Separate-process measurements remained inconsistent, including slower results +for some cases, even with CPU affinity and CPU-time diagnostics. The shared host, +JIT warmup and workload mix limit the confidence of those comparisons. The paired +runs are the evidence for the gains above; they do not establish a universal +speedup across JS engines or application workloads. Confirm on an idle target +machine before using the percentages as release guarantees. Reachable output +object counts are unchanged in all nine fixtures. + +[Recorded results](results/js-specialization/) include both paired summaries, +individual samples from the second run, source hashes, separate-process wall/CPU +measurements, and bundle sizes. Reproduce with `compare-conversion.js` as described +in [README.md](README.md); on Linux, prefix commands with `taskset -c ` to hold +CPU affinity constant. Default affinity is unrestricted. Do not combine these +ratios with the older fixture-version 2 table above. + +Validation: **249 existing/new JS tests pass** (248 main, one persisted-query), +including 145 utility tests; both runtime modules retain **100% statement, branch, +function and line coverage**. All **18 targeted mutation checks**, native +ESM/CommonJS parity, and artifact size budgets pass. The six new tests exercise +opaque-list nulls/holes/inherited elements/cyclic values and generic-object +metadata, inherited keys, own-key order and identity preservation in both nullable +directions. Coverage and mutations provide evidence, not exhaustive correctness. diff --git a/packages/rescript-relay/benchmarks/SIZE.md b/packages/rescript-relay/benchmarks/SIZE.md index 26f489db..f18fb3e2 100644 --- a/packages/rescript-relay/benchmarks/SIZE.md +++ b/packages/rescript-relay/benchmarks/SIZE.md @@ -157,3 +157,18 @@ an independent evaluator at depths 1–3 in both nullable directions, including sparse arrays, option markers, and falsey values. The full mounted suite also uses the regenerated artifacts. More elaborate format compression was intentionally left out. + +## JavaScript hot-path specialization + +Generic records and opaque lists now use dedicated loops. This adds **79 gzip +bytes** to the complete CommonJS-entry runtime bundle (2,330 → 2,409), or **82 +bytes** to the equivalent native ESM bundle (2,238 → 2,320). Both measurements use +esbuild 0.25.12, `bundle: true`, `minify: true`, `format: "esm"`, gzip level 9, and +retain all four public exports. CommonJS module wrappers explain the different +absolute sizes. Minified/Brotli details are in +[`results/js-specialization`](results/js-specialization/). + +The 129-artifact generated-code bundles and their budgets are unchanged. This is +a shared runtime cost, not an additional cost per generated fragment or query. +See [the performance results](RESULTS.md#further-javascript-specialization-fixture-version-3) +for measurements and their limits. diff --git a/packages/rescript-relay/benchmarks/compare-conversion.js b/packages/rescript-relay/benchmarks/compare-conversion.js new file mode 100644 index 00000000..51d46148 --- /dev/null +++ b/packages/rescript-relay/benchmarks/compare-conversion.js @@ -0,0 +1,110 @@ +#!/usr/bin/env node +// Alternate order within each pair to reduce temporal bias. These are warm +// microbenchmarks, not end-to-end latency or proof of parity across JS engines. +const {performance} = require("perf_hooks"); +const fs = require("fs"); +const assert = require("assert/strict"); +const os = require("os"); +const crypto = require("crypto"); +const v8 = require("v8"); +const path = require("path"); +const {cases, converters} = require("./fixtures"); +const args = process.argv.slice(2); +const option = name => { + const index = args.indexOf(name); + return index < 0 ? undefined : args[index + 1]; +}; +if (!option("--baseline") || !option("--output")) { + throw new Error("Usage: compare-conversion.js --baseline --output [--candidate ] [--legacy]"); +} +const baselinePath = path.resolve(option("--baseline")); +const candidatePath = option("--candidate") ? path.resolve(option("--candidate")) : require.resolve("../src/utils"); +const baseline = require(baselinePath); +const candidate = require(candidatePath); +const samples = 31; +const targetSampleMs = 20; +let sink; +function batch(convert, root, count) { + const start = performance.now(); + for (let i = 0; i < count; i++) sink = convert(root); + return (performance.now() - start) * 1e6 / count; +} +function median(values) { + return [...values].sort((a, b) => a - b)[Math.floor(values.length / 2)]; +} +function hash(filename) { + return crypto.createHash("sha256") + .update(fs.readFileSync(require.resolve(filename))).digest("hex"); +} +function build(runtime, fixture, mode) { + if (mode === "legacy") { + return value => runtime.traverser(value, fixture.maps, converters, fixture.nullable); + } + if (Object.keys(fixture.plan.roots).length === 1 && fixture.plan.roots.__root.length === 0) { + return value => runtime.convertWithoutPlan(value, fixture.nullable); + } + return runtime.prepareConversion(fixture.plan, converters, fixture.nullable); +} +const initialLoad = os.loadavg(); +const results = []; +for (const mode of [args.includes("--legacy") ? "legacy" : "prepared"]) { + for (const fixture of cases) { + const before = v8.deserialize(v8.serialize(fixture.root)); + const original = build(baseline, fixture, mode); + const ported = build(candidate, fixture, mode); + assert.deepEqual(ported(fixture.root), original(fixture.root), fixture.name); + let count = 100; + while (Math.min(batch(original, fixture.root, count), batch(ported, fixture.root, count)) * count < targetSampleMs * 1e6) { + count *= 2; + } + const measurements = []; + for (let i = 0; i < samples; i++) { + let baselineNs, candidateNs; + if (i % 2) { + candidateNs = batch(ported, fixture.root, count); + baselineNs = batch(original, fixture.root, count); + } else { + baselineNs = batch(original, fixture.root, count); + candidateNs = batch(ported, fixture.root, count); + } + measurements.push({baselineNs, candidateNs}); + } + assert.deepEqual(fixture.root, before, fixture.name + ": input mutated"); + const result = { + mode, + name: fixture.name, + count, + baselineNs: median(measurements.map(sample => sample.baselineNs)), + candidateNs: median(measurements.map(sample => sample.candidateNs)), + ratio: median(measurements.map(sample => sample.candidateNs / sample.baselineNs)), + samples: measurements, + }; + results.push(result); + console.log(mode, fixture.name, Math.round(result.baselineNs), Math.round(result.candidateNs), (result.ratio * 100 - 100).toFixed(1) + "%"); + } +} +function preparedHash(entry) { + const filename = path.join(path.dirname(entry), "prepareConversion.js"); + return fs.existsSync(filename) ? hash(filename) : null; +} +const report = { + fixtureVersion: 3, + node: process.version, + cpu: os.cpus()[0].model, + cpuAffinity: os.platform() === "linux" ? fs.readFileSync("/proc/self/status", "utf8").match(/^Cpus_allowed_list:\s*(.+)$/m)[1] : null, + samples, + targetSampleMs, + initialLoad, + finalLoad: os.loadavg(), + implementations: {baseline: baselinePath, candidate: candidatePath}, + sha256: { + baseline: hash(baselinePath), + preparedBaseline: preparedHash(baselinePath), + candidate: hash(candidatePath), + preparedCandidate: preparedHash(candidatePath), + fixtures: hash("./fixtures"), + }, + results, +}; +fs.writeFileSync(option("--output"), JSON.stringify(report, null, 2) + "\n"); +if (!sink) throw new Error("Missing benchmark result"); diff --git a/packages/rescript-relay/benchmarks/conversion.js b/packages/rescript-relay/benchmarks/conversion.js index c60bd644..1df32b94 100644 --- a/packages/rescript-relay/benchmarks/conversion.js +++ b/packages/rescript-relay/benchmarks/conversion.js @@ -50,10 +50,23 @@ const prepared = args.includes("--prepared"); if (prepared && !prepareConversion) throw new Error("Implementation has no prepared converter"); let sink; +const cpuTiming = args.includes("--cpu-time") + ? typeof process.threadCpuUsage === "function" ? "thread" : "process" + : undefined; +const readCpu = cpuTiming === "thread" + ? process.threadCpuUsage.bind(process) + : cpuTiming === "process" ? process.cpuUsage.bind(process) : undefined; +let lastCpuNs; function batch(fixture, count) { + const cpuStart = readCpu && readCpu(); const start = performance.now(); for (let i = 0; i < count; i++) sink = fixture.convert(fixture.root); - return performance.now() - start; + const elapsed = performance.now() - start; + if (readCpu) { + const cpu = readCpu(cpuStart); + lastCpuNs = (cpu.user + cpu.system) * 1000; + } + return elapsed; } const results = cases.map((fixture) => { const before = v8.deserialize(v8.serialize(fixture.root)); @@ -89,10 +102,13 @@ const results = cases.map((fixture) => { // Calibrate outside the measured samples; warm the same call site first. let iterations = 100; while (batch(fixture, iterations) < duration) iterations *= 2; - const values = Array.from( - { length: samples }, - () => (batch(fixture, iterations) * 1e6) / iterations, - ).sort((a, b) => a - b); + const cpuSamples = []; + const values = Array.from({ length: samples }, () => { + const wallNs = (batch(fixture, iterations) * 1e6) / iterations; + if (readCpu) cpuSamples.push({ wallNs, cpuNs: lastCpuNs / iterations }); + return wallNs; + }).sort((a, b) => a - b); + const cpuValues = cpuSamples.map(sample => sample.cpuNs).sort((a, b) => a - b); const median = values[Math.floor(values.length / 2)]; return { name: fixture.name, @@ -100,6 +116,8 @@ const results = cases.map((fixture) => { newOutputObjects, preparationNs, medianNs: median, + medianCpuNs: readCpu ? cpuValues[Math.floor(cpuValues.length / 2)] : undefined, + cpuSamples: readCpu ? cpuSamples : undefined, p10Ns: values[Math.floor(values.length * 0.1)], p90Ns: values[Math.floor(values.length * 0.9)], opsPerSecond: 1e9 / median, @@ -113,6 +131,7 @@ const report = { cpu: os.cpus()[0].model, samples, durationMs: duration, + cpuTiming, implementation: implementation || "src/utils.js", results, }; @@ -120,6 +139,7 @@ console.table( results.map((r) => ({ case: r.name, "median ns": Math.round(r.medianNs), + ...(readCpu ? { "CPU ns": Math.round(r.medianCpuNs) } : {}), "p10 ns": Math.round(r.p10Ns), "p90 ns": Math.round(r.p90Ns), "ops/sec": Math.round(r.opsPerSecond), diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/README.md b/packages/rescript-relay/benchmarks/rescript-runtime/README.md index 8a4eb714..647f5e80 100644 --- a/packages/rescript-relay/benchmarks/rescript-runtime/README.md +++ b/packages/rescript-relay/benchmarks/rescript-runtime/README.md @@ -42,8 +42,10 @@ production rollout. Three runs used Node 24.16.0 on AMD RYZEN AI MAX+ 395, with 31 alternating baseline/candidate pairs per case. Each pair reverses execution order; calibration -and preparation are outside warm timings. All comparisons use the same fixture -version and the JavaScript runtime from `b0f009a`. The shared host was busy, so +and preparation are outside warm timings. All recorded comparisons use the same fixture +version and the JavaScript runtime from `b0f009a`. The JavaScript runtime has since +been optimized further; check out `3de062b` to reproduce these historical results, +or use the commands above to compare against the current runtime. The shared host was busy, so small differences and individual timings are noisy. These are conversion microbenchmarks, not app latency measurements or cross-engine guarantees. diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/artifact-size.json b/packages/rescript-relay/benchmarks/results/js-specialization/artifact-size.json new file mode 100644 index 00000000..44689418 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/artifact-size.json @@ -0,0 +1,792 @@ +{ + "fixtureVersion": 1, + "esbuild": "0.25.12", + "node": "v24.16.0", + "artifactCount": 129, + "combined": { + "minified": 272639, + "gzip": 36319, + "brotli": 26233 + }, + "separate": { + "minified": 302536, + "gzip": 118381, + "brotli": 104973 + }, + "files": [ + { + "path": "__tests__/__generated__/GroupAvatar_group_graphql.bs.js", + "minified": 711, + "gzip": 447, + "brotli": 384 + }, + { + "path": "__tests__/__generated__/HasNameComponent_hasName_graphql.bs.js", + "minified": 805, + "gzip": 467, + "brotli": 400 + }, + { + "path": "__tests__/__generated__/LocalUser____relay_model_instance_graphql.bs.js", + "minified": 1059, + "gzip": 579, + "brotli": 506 + }, + { + "path": "__tests__/__generated__/LocalUser__id_graphql.bs.js", + "minified": 747, + "gzip": 462, + "brotli": 399 + }, + { + "path": "__tests__/__generated__/LocalUser_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/Query_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/RichContent_content_graphql.bs.js", + "minified": 722, + "gzip": 447, + "brotli": 380 + }, + { + "path": "__tests__/__generated__/TestAliasedFragmentsQuery_graphql.bs.js", + "minified": 3136, + "gzip": 1125, + "brotli": 1003 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.bs.js", + "minified": 732, + "gzip": 455, + "brotli": 394 + }, + { + "path": "__tests__/__generated__/TestAliasedFragments_userLastName_graphql.bs.js", + "minified": 730, + "gzip": 454, + "brotli": 391 + }, + { + "path": "__tests__/__generated__/TestArrayUnderlyingScalarSiblingQuery_graphql.bs.js", + "minified": 2792, + "gzip": 1191, + "brotli": 1066 + }, + { + "path": "__tests__/__generated__/TestCatchLoggedInUserPropQuery_graphql.bs.js", + "minified": 2721, + "gzip": 1165, + "brotli": 1035 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropNestedQuery_graphql.bs.js", + "minified": 3889, + "gzip": 1386, + "brotli": 1260 + }, + { + "path": "__tests__/__generated__/TestCatchMemberPropQuery_graphql.bs.js", + "minified": 3020, + "gzip": 1285, + "brotli": 1159 + }, + { + "path": "__tests__/__generated__/TestCatchMembersPropQuery_graphql.bs.js", + "minified": 3708, + "gzip": 1381, + "brotli": 1244 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMemberQuery_graphql.bs.js", + "minified": 3073, + "gzip": 1217, + "brotli": 1078 + }, + { + "path": "__tests__/__generated__/TestCatchUnionMember_member_graphql.bs.js", + "minified": 1472, + "gzip": 691, + "brotli": 604 + }, + { + "path": "__tests__/__generated__/TestCatchUser_user_graphql.bs.js", + "minified": 875, + "gzip": 542, + "brotli": 465 + }, + { + "path": "__tests__/__generated__/TestCodesplitQuery_graphql.bs.js", + "minified": 7005, + "gzip": 1782, + "brotli": 1615 + }, + { + "path": "__tests__/__generated__/TestCompileInterfacesFragment_user_graphql.bs.js", + "minified": 731, + "gzip": 458, + "brotli": 393 + }, + { + "path": "__tests__/__generated__/TestConnections2_user_graphql.bs.js", + "minified": 4007, + "gzip": 1328, + "brotli": 1202 + }, + { + "path": "__tests__/__generated__/TestConnections3_user_graphql.bs.js", + "minified": 2215, + "gzip": 817, + "brotli": 726 + }, + { + "path": "__tests__/__generated__/TestConnectionsQuery_graphql.bs.js", + "minified": 4183, + "gzip": 1508, + "brotli": 1348 + }, + { + "path": "__tests__/__generated__/TestConnections_AddFriendMutation_graphql.bs.js", + "minified": 2162, + "gzip": 856, + "brotli": 771 + }, + { + "path": "__tests__/__generated__/TestConnections_user_graphql.bs.js", + "minified": 2895, + "gzip": 1031, + "brotli": 928 + }, + { + "path": "__tests__/__generated__/TestCustomScalarAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2616, + "gzip": 1119, + "brotli": 992 + }, + { + "path": "__tests__/__generated__/TestCustomScalarsQuery_graphql.bs.js", + "minified": 4182, + "gzip": 1475, + "brotli": 1336 + }, + { + "path": "__tests__/__generated__/TestFragmentQuery_graphql.bs.js", + "minified": 4301, + "gzip": 1367, + "brotli": 1223 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredPlural_user_graphql.bs.js", + "minified": 903, + "gzip": 534, + "brotli": 463 + }, + { + "path": "__tests__/__generated__/TestFragmentRequiredQuery_graphql.bs.js", + "minified": 3467, + "gzip": 1182, + "brotli": 1050 + }, + { + "path": "__tests__/__generated__/TestFragmentRequired_user_graphql.bs.js", + "minified": 890, + "gzip": 525, + "brotli": 452 + }, + { + "path": "__tests__/__generated__/TestFragment_allowUnsafeEnum_graphql.bs.js", + "minified": 925, + "gzip": 524, + "brotli": 451 + }, + { + "path": "__tests__/__generated__/TestFragment_inline_graphql.bs.js", + "minified": 694, + "gzip": 430, + "brotli": 372 + }, + { + "path": "__tests__/__generated__/TestFragment_plural_user_graphql.bs.js", + "minified": 996, + "gzip": 531, + "brotli": 458 + }, + { + "path": "__tests__/__generated__/TestFragment_sub_user_graphql.bs.js", + "minified": 718, + "gzip": 450, + "brotli": 387 + }, + { + "path": "__tests__/__generated__/TestFragment_user_graphql.bs.js", + "minified": 1168, + "gzip": 600, + "brotli": 513 + }, + { + "path": "__tests__/__generated__/TestInputUnionQuery_graphql.bs.js", + "minified": 2163, + "gzip": 1037, + "brotli": 904 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadQuery_graphql.bs.js", + "minified": 5054, + "gzip": 1560, + "brotli": 1408 + }, + { + "path": "__tests__/__generated__/TestLocalPayloadViaNodeInterfaceQuery_graphql.bs.js", + "minified": 5686, + "gzip": 1693, + "brotli": 1525 + }, + { + "path": "__tests__/__generated__/TestLocalPayload_user_graphql.bs.js", + "minified": 2408, + "gzip": 847, + "brotli": 753 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedMeQuery_graphql.bs.js", + "minified": 2185, + "gzip": 961, + "brotli": 844 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersLinkedQuery_graphql.bs.js", + "minified": 2708, + "gzip": 1169, + "brotli": 1043 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralBestiesQuery_graphql.bs.js", + "minified": 2208, + "gzip": 963, + "brotli": 846 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersPluralQuery_graphql.bs.js", + "minified": 2192, + "gzip": 963, + "brotli": 843 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarMeQuery_graphql.bs.js", + "minified": 2183, + "gzip": 956, + "brotli": 844 + }, + { + "path": "__tests__/__generated__/TestMissingFieldHandlersScalarQuery_graphql.bs.js", + "minified": 2704, + "gzip": 1167, + "brotli": 1040 + }, + { + "path": "__tests__/__generated__/TestMutationInline_user_graphql.bs.js", + "minified": 698, + "gzip": 434, + "brotli": 376 + }, + { + "path": "__tests__/__generated__/TestMutationProvidedVariable_user_graphql.bs.js", + "minified": 898, + "gzip": 514, + "brotli": 443 + }, + { + "path": "__tests__/__generated__/TestMutationQuery_graphql.bs.js", + "minified": 3201, + "gzip": 1208, + "brotli": 1066 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusComplexMutation_graphql.bs.js", + "minified": 2404, + "gzip": 990, + "brotli": 882 + }, + { + "path": "__tests__/__generated__/TestMutationSetOnlineStatusMutation_graphql.bs.js", + "minified": 2994, + "gzip": 1025, + "brotli": 923 + }, + { + "path": "__tests__/__generated__/TestMutationWithInlineFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 2929, + "gzip": 1004, + "brotli": 900 + }, + { + "path": "__tests__/__generated__/TestMutationWithOnlyFragmentSetOnlineStatusMutation_graphql.bs.js", + "minified": 3910, + "gzip": 1231, + "brotli": 1116 + }, + { + "path": "__tests__/__generated__/TestMutationWithProvidedVariableFragmentMutation_graphql.bs.js", + "minified": 2788, + "gzip": 967, + "brotli": 880 + }, + { + "path": "__tests__/__generated__/TestMutation_user_graphql.bs.js", + "minified": 1757, + "gzip": 732, + "brotli": 645 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceOnAbstractTypeQuery_graphql.bs.js", + "minified": 3137, + "gzip": 1238, + "brotli": 1103 + }, + { + "path": "__tests__/__generated__/TestNodeInterfaceQuery_graphql.bs.js", + "minified": 3720, + "gzip": 1318, + "brotli": 1193 + }, + { + "path": "__tests__/__generated__/TestNodeInterface_user_graphql.bs.js", + "minified": 720, + "gzip": 454, + "brotli": 387 + }, + { + "path": "__tests__/__generated__/TestNonReactQuery_graphql.bs.js", + "minified": 2468, + "gzip": 1077, + "brotli": 944 + }, + { + "path": "__tests__/__generated__/TestNonReact_user_graphql.bs.js", + "minified": 914, + "gzip": 519, + "brotli": 447 + }, + { + "path": "__tests__/__generated__/TestNullableScalarsAfterCustomScalarArrayQuery_graphql.bs.js", + "minified": 2798, + "gzip": 1170, + "brotli": 1035 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesMutation_graphql.bs.js", + "minified": 2713, + "gzip": 1016, + "brotli": 908 + }, + { + "path": "__tests__/__generated__/TestNullableVariablesQuery_graphql.bs.js", + "minified": 2141, + "gzip": 948, + "brotli": 834 + }, + { + "path": "__tests__/__generated__/TestObserverQuery_graphql.bs.js", + "minified": 1893, + "gzip": 922, + "brotli": 813 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeQuery_graphql.bs.js", + "minified": 4371, + "gzip": 1458, + "brotli": 1305 + }, + { + "path": "__tests__/__generated__/TestPaginationInNodeRefetchQuery_graphql.bs.js", + "minified": 4990, + "gzip": 1625, + "brotli": 1474 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_query_graphql.bs.js", + "minified": 2756, + "gzip": 1055, + "brotli": 940 + }, + { + "path": "__tests__/__generated__/TestPaginationInNode_user_graphql.bs.js", + "minified": 1062, + "gzip": 549, + "brotli": 475 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionQuery_graphql.bs.js", + "minified": 4940, + "gzip": 1564, + "brotli": 1406 + }, + { + "path": "__tests__/__generated__/TestPaginationUnionRefetchQuery_graphql.bs.js", + "minified": 5625, + "gzip": 1722, + "brotli": 1554 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_query_graphql.bs.js", + "minified": 3741, + "gzip": 1239, + "brotli": 1113 + }, + { + "path": "__tests__/__generated__/TestPaginationUnion_user_graphql.bs.js", + "minified": 993, + "gzip": 541, + "brotli": 471 + }, + { + "path": "__tests__/__generated__/TestParseCustomScalarArrayQuery_graphql.bs.js", + "minified": 2722, + "gzip": 1112, + "brotli": 991 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationQuery_graphql.bs.js", + "minified": 3657, + "gzip": 1295, + "brotli": 1149 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePaginationRefetchQuery_graphql.bs.js", + "minified": 4215, + "gzip": 1439, + "brotli": 1293 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user__edges_graphql.bs.js", + "minified": 1106, + "gzip": 555, + "brotli": 486 + }, + { + "path": "__tests__/__generated__/TestPrefetchablePagination_user_graphql.bs.js", + "minified": 2208, + "gzip": 879, + "brotli": 776 + }, + { + "path": "__tests__/__generated__/TestProvidedVariablesQuery_graphql.bs.js", + "minified": 5647, + "gzip": 1538, + "brotli": 1388 + }, + { + "path": "__tests__/__generated__/TestProvidedVariables_user_graphql.bs.js", + "minified": 1581, + "gzip": 572, + "brotli": 504 + }, + { + "path": "__tests__/__generated__/TestQueryInputObjectsQuery_graphql.bs.js", + "minified": 2061, + "gzip": 1018, + "brotli": 892 + }, + { + "path": "__tests__/__generated__/TestQuery_graphql.bs.js", + "minified": 2613, + "gzip": 1106, + "brotli": 978 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeQuery_graphql.bs.js", + "minified": 3713, + "gzip": 1409, + "brotli": 1274 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNodeRefetchQuery_graphql.bs.js", + "minified": 3822, + "gzip": 1412, + "brotli": 1264 + }, + { + "path": "__tests__/__generated__/TestRefetchingInNode_user_graphql.bs.js", + "minified": 1705, + "gzip": 769, + "brotli": 668 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgsRefetchQuery_graphql.bs.js", + "minified": 2193, + "gzip": 1016, + "brotli": 902 + }, + { + "path": "__tests__/__generated__/TestRefetchingNoArgs_query_graphql.bs.js", + "minified": 988, + "gzip": 558, + "brotli": 485 + }, + { + "path": "__tests__/__generated__/TestRefetchingQuery_graphql.bs.js", + "minified": 3719, + "gzip": 1387, + "brotli": 1234 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgsRefetchQuery_graphql.bs.js", + "minified": 2235, + "gzip": 1022, + "brotli": 905 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordNoArgs_query_graphql.bs.js", + "minified": 1000, + "gzip": 561, + "brotli": 489 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordQuery_graphql.bs.js", + "minified": 3761, + "gzip": 1393, + "brotli": 1240 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecordRefetchQuery_graphql.bs.js", + "minified": 4514, + "gzip": 1581, + "brotli": 1426 + }, + { + "path": "__tests__/__generated__/TestRefetchingRecord_user_graphql.bs.js", + "minified": 2080, + "gzip": 827, + "brotli": 721 + }, + { + "path": "__tests__/__generated__/TestRefetchingRefetchQuery_graphql.bs.js", + "minified": 4472, + "gzip": 1574, + "brotli": 1420 + }, + { + "path": "__tests__/__generated__/TestRefetching_user_graphql.bs.js", + "minified": 2068, + "gzip": 823, + "brotli": 721 + }, + { + "path": "__tests__/__generated__/TestRelayResolversAllQuery_graphql.bs.js", + "minified": 5361, + "gzip": 1536, + "brotli": 1386 + }, + { + "path": "__tests__/__generated__/TestRelayResolversQuery_graphql.bs.js", + "minified": 3046, + "gzip": 1181, + "brotli": 1052 + }, + { + "path": "__tests__/__generated__/TestRelayResolvers_user_graphql.bs.js", + "minified": 1300, + "gzip": 625, + "brotli": 542 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver2_graphql.bs.js", + "minified": 794, + "gzip": 465, + "brotli": 395 + }, + { + "path": "__tests__/__generated__/TestRelayUserResolver_graphql.bs.js", + "minified": 793, + "gzip": 463, + "brotli": 395 + }, + { + "path": "__tests__/__generated__/TestRequiredFieldLoggerQuery_graphql.bs.js", + "minified": 2191, + "gzip": 967, + "brotli": 855 + }, + { + "path": "__tests__/__generated__/TestSerializeCustomScalarArrayMutation_graphql.bs.js", + "minified": 1796, + "gzip": 841, + "brotli": 735 + }, + { + "path": "__tests__/__generated__/TestSerializeMultipleCustomScalarsMutation_graphql.bs.js", + "minified": 1829, + "gzip": 827, + "brotli": 719 + }, + { + "path": "__tests__/__generated__/TestSubscriptionProvidedVariable_user_graphql.bs.js", + "minified": 902, + "gzip": 515, + "brotli": 443 + }, + { + "path": "__tests__/__generated__/TestSubscriptionQuery_graphql.bs.js", + "minified": 2542, + "gzip": 1073, + "brotli": 942 + }, + { + "path": "__tests__/__generated__/TestSubscriptionUserUpdatedSubscription_graphql.bs.js", + "minified": 2552, + "gzip": 952, + "brotli": 837 + }, + { + "path": "__tests__/__generated__/TestSubscriptionWithProvidedVariableFragmentSubscription_graphql.bs.js", + "minified": 3038, + "gzip": 1066, + "brotli": 953 + }, + { + "path": "__tests__/__generated__/TestSubscription_user_graphql.bs.js", + "minified": 1061, + "gzip": 535, + "brotli": 455 + }, + { + "path": "__tests__/__generated__/TestTestingHelpersQuery_graphql.bs.js", + "minified": 3448, + "gzip": 1298, + "brotli": 1170 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_plural_user_graphql.bs.js", + "minified": 1002, + "gzip": 538, + "brotli": 466 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_sub_user_graphql.bs.js", + "minified": 724, + "gzip": 458, + "brotli": 390 + }, + { + "path": "__tests__/__generated__/TestTestingHelpers_user_graphql.bs.js", + "minified": 1180, + "gzip": 607, + "brotli": 521 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentQuery_graphql.bs.js", + "minified": 3556, + "gzip": 1264, + "brotli": 1124 + }, + { + "path": "__tests__/__generated__/TestUnionFragmentUser_user_graphql.bs.js", + "minified": 923, + "gzip": 520, + "brotli": 448 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_member_graphql.bs.js", + "minified": 1547, + "gzip": 696, + "brotli": 609 + }, + { + "path": "__tests__/__generated__/TestUnionFragment_plural_member_graphql.bs.js", + "minified": 1561, + "gzip": 707, + "brotli": 634 + }, + { + "path": "__tests__/__generated__/TestUnionsQuery_graphql.bs.js", + "minified": 5037, + "gzip": 1522, + "brotli": 1380 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragmentsQuery_graphql.bs.js", + "minified": 2816, + "gzip": 1121, + "brotli": 997 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_query_graphql.bs.js", + "minified": 1248, + "gzip": 607, + "brotli": 517 + }, + { + "path": "__tests__/__generated__/TestUpdatableFragments_updatableUser_graphql.bs.js", + "minified": 678, + "gzip": 363, + "brotli": 321 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_UpdatableQuery_graphql.bs.js", + "minified": 1298, + "gzip": 610, + "brotli": 529 + }, + { + "path": "__tests__/__generated__/TestUpdatableQuery_graphql.bs.js", + "minified": 2607, + "gzip": 1046, + "brotli": 936 + }, + { + "path": "__tests__/__generated__/UserAvatar_user_graphql.bs.js", + "minified": 1049, + "gzip": 572, + "brotli": 494 + }, + { + "path": "__tests__/__generated__/UserMeta____relay_model_instance_graphql.bs.js", + "minified": 785, + "gzip": 476, + "brotli": 404 + }, + { + "path": "__tests__/__generated__/UserMeta_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests__/__generated__/UserName_user_graphql.bs.js", + "minified": 785, + "gzip": 458, + "brotli": 393 + }, + { + "path": "__tests__/__generated__/User_relayResolvers_graphql.bs.js", + "minified": 0, + "gzip": 20, + "brotli": 1 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQueryProvidedVariables_user_graphql.bs.js", + "minified": 1418, + "gzip": 570, + "brotli": 499 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_graphql.bs.js", + "minified": 5051, + "gzip": 1484, + "brotli": 1332 + }, + { + "path": "__tests_preloaded__/__generated__/TestPreloadedQuery_preloadable_graphql.bs.js", + "minified": 2236, + "gzip": 845, + "brotli": 759 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/paired-final.json b/packages/rescript-relay/benchmarks/results/js-specialization/paired-final.json new file mode 100644 index 00000000..3580295f --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/paired-final.json @@ -0,0 +1,1237 @@ +{ + "fixtureVersion": 3, + "node": "v24.16.0", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "cpuAffinity": "7", + "samples": 31, + "targetSampleMs": 20, + "initialLoad": [ + 18.66, + 18.35, + 19.61 + ], + "finalLoad": [ + 18.51, + 18.31, + 19.56 + ], + "implementations": { + "baseline": "/tmp/relay-js-sweep/baseline/utils.js", + "candidate": "/tmp/rescript-relay-conversion-perf/packages/rescript-relay/src/utils.js" + }, + "sha256": { + "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", + "candidate": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedCandidate": "db39247dc78284162c7fe25551523d1681c4e469d37fceb7e24912b542a2e5c9", + "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" + }, + "results": [ + { + "mode": "prepared", + "name": "small fragment", + "count": 409600, + "baselineNs": 101.97609375000027, + "candidateNs": 93.63988037109361, + "ratio": 0.911205684427288, + "samples": [ + { + "baselineNs": 100.61977294921871, + "candidateNs": 90.84837646484378 + }, + { + "baselineNs": 100.75635742187491, + "candidateNs": 91.80976562499998 + }, + { + "baselineNs": 103.16593994140631, + "candidateNs": 93.6941845703125 + }, + { + "baselineNs": 99.6786108398437, + "candidateNs": 92.54249755859368 + }, + { + "baselineNs": 134.55474365234366, + "candidateNs": 111.5397485351563 + }, + { + "baselineNs": 98.84574218750025, + "candidateNs": 90.67483154296868 + }, + { + "baselineNs": 99.98926025390625, + "candidateNs": 90.29442626953127 + }, + { + "baselineNs": 99.4406372070311, + "candidateNs": 90.73456298828108 + }, + { + "baselineNs": 98.90339355468736, + "candidateNs": 95.48519042968745 + }, + { + "baselineNs": 100.15113525390639, + "candidateNs": 90.33111572265607 + }, + { + "baselineNs": 121.9141601562501, + "candidateNs": 122.87283203125054 + }, + { + "baselineNs": 98.94866943359393, + "candidateNs": 90.9881665039064 + }, + { + "baselineNs": 101.673447265625, + "candidateNs": 93.51202880859388 + }, + { + "baselineNs": 99.20073242187522, + "candidateNs": 98.96845703124991 + }, + { + "baselineNs": 104.69392578125014, + "candidateNs": 91.67628417968754 + }, + { + "baselineNs": 101.97609375000027, + "candidateNs": 100.5320556640621 + }, + { + "baselineNs": 138.60612548828144, + "candidateNs": 134.11096191406236 + }, + { + "baselineNs": 107.09956787109343, + "candidateNs": 96.55134033203116 + }, + { + "baselineNs": 101.21009521484369, + "candidateNs": 119.24979980468709 + }, + { + "baselineNs": 126.60336669921836, + "candidateNs": 91.62239746093759 + }, + { + "baselineNs": 100.39953125, + "candidateNs": 119.72046386718783 + }, + { + "baselineNs": 183.26341064453078, + "candidateNs": 95.66017822265627 + }, + { + "baselineNs": 126.73002197265637, + "candidateNs": 93.63988037109361 + }, + { + "baselineNs": 129.81686279296855, + "candidateNs": 92.15538818359347 + }, + { + "baselineNs": 101.77635253906249, + "candidateNs": 94.67819824218738 + }, + { + "baselineNs": 127.6537646484377, + "candidateNs": 103.95960449218755 + }, + { + "baselineNs": 103.5758935546871, + "candidateNs": 94.03039306640659 + }, + { + "baselineNs": 106.15442382812535, + "candidateNs": 149.54958251953033 + }, + { + "baselineNs": 103.78309814453202, + "candidateNs": 92.74028076171948 + }, + { + "baselineNs": 102.98172851562536, + "candidateNs": 92.17762207031188 + }, + { + "baselineNs": 99.00397216796918, + "candidateNs": 90.59088378906232 + } + ] + }, + { + "mode": "prepared", + "name": "unchanged object", + "count": 819200, + "baselineNs": 57.85585937500004, + "candidateNs": 49.18847900390655, + "ratio": 0.8518584576886907, + "samples": [ + { + "baselineNs": 57.112375488281295, + "candidateNs": 48.563592529296535 + }, + { + "baselineNs": 56.940970458984054, + "candidateNs": 48.91904907226574 + }, + { + "baselineNs": 58.13724853515611, + "candidateNs": 48.95136108398424 + }, + { + "baselineNs": 58.262864990234476, + "candidateNs": 49.48025390624999 + }, + { + "baselineNs": 57.68380493164082, + "candidateNs": 49.63090454101537 + }, + { + "baselineNs": 63.46085937500024, + "candidateNs": 79.54098876953086 + }, + { + "baselineNs": 62.74087036132803, + "candidateNs": 58.41883666992176 + }, + { + "baselineNs": 68.73973022460954, + "candidateNs": 59.7001879882808 + }, + { + "baselineNs": 66.4359020996097, + "candidateNs": 63.16422851562531 + }, + { + "baselineNs": 67.74928466796837, + "candidateNs": 50.83255371093775 + }, + { + "baselineNs": 78.52408813476598, + "candidateNs": 48.905118408202334 + }, + { + "baselineNs": 56.42544555664153, + "candidateNs": 48.873272705077795 + }, + { + "baselineNs": 57.33201782226472, + "candidateNs": 48.2005651855466 + }, + { + "baselineNs": 57.25826904296904, + "candidateNs": 49.00488037109407 + }, + { + "baselineNs": 57.07322631835931, + "candidateNs": 48.61831054687516 + }, + { + "baselineNs": 76.85287597656188, + "candidateNs": 56.13781738281309 + }, + { + "baselineNs": 56.78581787109338, + "candidateNs": 48.43781738281261 + }, + { + "baselineNs": 57.153603515625036, + "candidateNs": 48.66701171875043 + }, + { + "baselineNs": 58.79461914062523, + "candidateNs": 49.29632446289078 + }, + { + "baselineNs": 58.03193481445312, + "candidateNs": 48.39604003906262 + }, + { + "baselineNs": 57.443836669921474, + "candidateNs": 61.369467773437776 + }, + { + "baselineNs": 56.97390624999966, + "candidateNs": 65.04063842773466 + }, + { + "baselineNs": 57.3483325195312, + "candidateNs": 51.23844604492223 + }, + { + "baselineNs": 58.24804199218825, + "candidateNs": 49.18847900390655 + }, + { + "baselineNs": 57.6477746582027, + "candidateNs": 48.99093749999972 + }, + { + "baselineNs": 56.982393798827864, + "candidateNs": 48.69511596679698 + }, + { + "baselineNs": 78.29868774414051, + "candidateNs": 58.60127319335939 + }, + { + "baselineNs": 57.07952514648507, + "candidateNs": 48.54974853515714 + }, + { + "baselineNs": 57.85585937500004, + "candidateNs": 50.296958007812755 + }, + { + "baselineNs": 61.29579345703129, + "candidateNs": 48.92166748046822 + }, + { + "baselineNs": 58.80549194335894, + "candidateNs": 51.6028552246095 + } + ] + }, + { + "mode": "prepared", + "name": "nullable query", + "count": 102400, + "baselineNs": 150.39659179687524, + "candidateNs": 121.40841796874469, + "ratio": 0.8109976437073325, + "samples": [ + { + "baselineNs": 150.82689453125298, + "candidateNs": 122.490830078128 + }, + { + "baselineNs": 153.11520507812483, + "candidateNs": 126.57667968750452 + }, + { + "baselineNs": 154.33058593750104, + "candidateNs": 124.04954101563172 + }, + { + "baselineNs": 146.09148437500608, + "candidateNs": 122.96360351562006 + }, + { + "baselineNs": 148.65794921875343, + "candidateNs": 118.6480273437507 + }, + { + "baselineNs": 146.67754882812469, + "candidateNs": 118.95514648437633 + }, + { + "baselineNs": 150.39659179687524, + "candidateNs": 123.02005859375242 + }, + { + "baselineNs": 148.088125000001, + "candidateNs": 121.40841796874469 + }, + { + "baselineNs": 149.74859375000094, + "candidateNs": 118.78402343749705 + }, + { + "baselineNs": 152.00167968749236, + "candidateNs": 130.23515625000036 + }, + { + "baselineNs": 149.78705078124932, + "candidateNs": 118.23219726562861 + }, + { + "baselineNs": 148.54338867187343, + "candidateNs": 118.81141601562284 + }, + { + "baselineNs": 148.29016601562552, + "candidateNs": 123.51748046874889 + }, + { + "baselineNs": 151.31072265624823, + "candidateNs": 122.07715820312437 + }, + { + "baselineNs": 151.28273437500005, + "candidateNs": 119.07432617187297 + }, + { + "baselineNs": 169.55270507812872, + "candidateNs": 119.64169921875546 + }, + { + "baselineNs": 273.3397460937503, + "candidateNs": 216.94490234374973 + }, + { + "baselineNs": 149.42161132812436, + "candidateNs": 124.31273437500501 + }, + { + "baselineNs": 147.00239257813053, + "candidateNs": 120.10722656250474 + }, + { + "baselineNs": 149.32014648437075, + "candidateNs": 119.7609667968802 + }, + { + "baselineNs": 148.5837988281258, + "candidateNs": 119.26569335937387 + }, + { + "baselineNs": 151.40005859374915, + "candidateNs": 120.4606347656334 + }, + { + "baselineNs": 149.3244433593688, + "candidateNs": 124.10286132812587 + }, + { + "baselineNs": 146.8478906250059, + "candidateNs": 119.84090820312154 + }, + { + "baselineNs": 146.6446777343755, + "candidateNs": 120.19724609375615 + }, + { + "baselineNs": 154.2596582031308, + "candidateNs": 131.27648437500028 + }, + { + "baselineNs": 240.52862304687395, + "candidateNs": 247.20266601562457 + }, + { + "baselineNs": 154.96225585938106, + "candidateNs": 184.80418945312493 + }, + { + "baselineNs": 155.35312499999955, + "candidateNs": 120.54663085938165 + }, + { + "baselineNs": 163.4922363281266, + "candidateNs": 122.47009765625094 + }, + { + "baselineNs": 161.0586328125052, + "candidateNs": 121.05071289062685 + } + ] + }, + { + "mode": "prepared", + "name": "connection / 100 rows", + "count": 1600, + "baselineNs": 20627.377499999966, + "candidateNs": 16061.450000000263, + "ratio": 0.7978602752308714, + "samples": [ + { + "baselineNs": 19792.75687499978, + "candidateNs": 15825.009375000149 + }, + { + "baselineNs": 20442.534375000036, + "candidateNs": 16235.904375000133 + }, + { + "baselineNs": 19411.39249999992, + "candidateNs": 15922.431249999818 + }, + { + "baselineNs": 19921.13687500023, + "candidateNs": 15894.283749999546 + }, + { + "baselineNs": 22088.701874999973, + "candidateNs": 16732.956249999803 + }, + { + "baselineNs": 21853.450624999485, + "candidateNs": 15765.38375000041 + }, + { + "baselineNs": 35173.21999999978, + "candidateNs": 17399.35937499979 + }, + { + "baselineNs": 20438.85875000001, + "candidateNs": 16195.784999999889 + }, + { + "baselineNs": 19944.75687500028, + "candidateNs": 16476.20874999973 + }, + { + "baselineNs": 19709.017499999958, + "candidateNs": 15825.166249999826 + }, + { + "baselineNs": 20073.763124999576, + "candidateNs": 15833.381250000117 + }, + { + "baselineNs": 21501.91124999992, + "candidateNs": 16044.85000000011 + }, + { + "baselineNs": 20068.603125000096, + "candidateNs": 16022.620625000172 + }, + { + "baselineNs": 20122.96187499999, + "candidateNs": 16061.450000000263 + }, + { + "baselineNs": 24133.296250000174, + "candidateNs": 27438.598749999983 + }, + { + "baselineNs": 21772.830000000453, + "candidateNs": 18929.32500000029 + }, + { + "baselineNs": 21122.175000000425, + "candidateNs": 16312.711875000334 + }, + { + "baselineNs": 20627.377499999966, + "candidateNs": 16372.988749999422 + }, + { + "baselineNs": 19893.854375000046, + "candidateNs": 15750.431249999792 + }, + { + "baselineNs": 19688.196875000584, + "candidateNs": 16301.516249999395 + }, + { + "baselineNs": 19562.546875000637, + "candidateNs": 16053.459375000331 + }, + { + "baselineNs": 21263.466875000177, + "candidateNs": 16827.979374999133 + }, + { + "baselineNs": 25625.233749999552, + "candidateNs": 25746.213125000846 + }, + { + "baselineNs": 21296.554374999916, + "candidateNs": 15969.331874999853 + }, + { + "baselineNs": 21001.616249999413, + "candidateNs": 15830.37562500067 + }, + { + "baselineNs": 21021.140624999363, + "candidateNs": 15915.574375000004 + }, + { + "baselineNs": 20868.87812499981, + "candidateNs": 16024.235625000074 + }, + { + "baselineNs": 19349.319374999825, + "candidateNs": 15662.690625000549 + }, + { + "baselineNs": 19805.129999999735, + "candidateNs": 16928.78250000035 + }, + { + "baselineNs": 21146.84062500032, + "candidateNs": 17599.04312499998 + }, + { + "baselineNs": 21598.932499999817, + "candidateNs": 28216.625000000022 + } + ] + }, + { + "mode": "prepared", + "name": "plural fragment / 100 rows", + "count": 3200, + "baselineNs": 14628.395000000295, + "candidateNs": 12268.573437499981, + "ratio": 0.8496155826051577, + "samples": [ + { + "baselineNs": 14479.191250000555, + "candidateNs": 12143.57781250044 + }, + { + "baselineNs": 14913.865624999971, + "candidateNs": 13034.144999999739 + }, + { + "baselineNs": 14346.249687499721, + "candidateNs": 12230.338749999986 + }, + { + "baselineNs": 15792.00031250025, + "candidateNs": 18270.09531249985 + }, + { + "baselineNs": 14313.494062499785, + "candidateNs": 12197.250937499577 + }, + { + "baselineNs": 14617.76562500006, + "candidateNs": 12073.448437500361 + }, + { + "baselineNs": 14639.92937499995, + "candidateNs": 12213.01843750041 + }, + { + "baselineNs": 14479.229062499711, + "candidateNs": 12268.573437499981 + }, + { + "baselineNs": 14542.614062499979, + "candidateNs": 18010.90249999959 + }, + { + "baselineNs": 14525.50062499995, + "candidateNs": 14588.10968749958 + }, + { + "baselineNs": 17255.262187499626, + "candidateNs": 22001.493125000023 + }, + { + "baselineNs": 22177.06562500041, + "candidateNs": 19172.278124999593 + }, + { + "baselineNs": 26595.33281249992, + "candidateNs": 20125.84562500024 + }, + { + "baselineNs": 14628.395000000295, + "candidateNs": 16311.118750000447 + }, + { + "baselineNs": 14586.33124999949, + "candidateNs": 12161.727812500088 + }, + { + "baselineNs": 14408.958750000238, + "candidateNs": 12613.412499999868 + }, + { + "baselineNs": 14715.597500000398, + "candidateNs": 12097.109062499954 + }, + { + "baselineNs": 14423.645625000177, + "candidateNs": 12215.07562499994 + }, + { + "baselineNs": 21461.2784374998, + "candidateNs": 13226.605625000047 + }, + { + "baselineNs": 14313.424999999712, + "candidateNs": 12174.17624999996 + }, + { + "baselineNs": 14648.010312500333, + "candidateNs": 12097.321874999807 + }, + { + "baselineNs": 14405.702500000074, + "candidateNs": 12044.265312499647 + }, + { + "baselineNs": 14383.113124999909, + "candidateNs": 12254.772500000401 + }, + { + "baselineNs": 20846.720312499656, + "candidateNs": 12076.35718749998 + }, + { + "baselineNs": 16352.972812500184, + "candidateNs": 12127.860937500258 + }, + { + "baselineNs": 14479.13812500019, + "candidateNs": 12129.435625000157 + }, + { + "baselineNs": 14486.909062500217, + "candidateNs": 12906.388124999921 + }, + { + "baselineNs": 16013.111875000162, + "candidateNs": 13604.989374999832 + }, + { + "baselineNs": 16310.123124999904, + "candidateNs": 12683.504375000326 + }, + { + "baselineNs": 15663.601249999601, + "candidateNs": 19937.6806250001 + }, + { + "baselineNs": 14753.719374999719, + "candidateNs": 13483.068437499809 + } + ] + }, + { + "mode": "prepared", + "name": "union list / 100 rows", + "count": 1600, + "baselineNs": 21162.050000000363, + "candidateNs": 15568.825624999363, + "ratio": 0.749143054513265, + "samples": [ + { + "baselineNs": 19146.31062500007, + "candidateNs": 15568.825624999363 + }, + { + "baselineNs": 21122.18812500032, + "candidateNs": 15172.457500000291 + }, + { + "baselineNs": 20671.642500000187, + "candidateNs": 22422.2068749998 + }, + { + "baselineNs": 22513.12250000069, + "candidateNs": 23150.558124999632 + }, + { + "baselineNs": 20833.99312499978, + "candidateNs": 15138.286249999737 + }, + { + "baselineNs": 26052.51062499974, + "candidateNs": 15164.849999999888 + }, + { + "baselineNs": 21868.841874999132, + "candidateNs": 15156.621250000626 + }, + { + "baselineNs": 20558.52874999914, + "candidateNs": 15163.415624999743 + }, + { + "baselineNs": 20324.36749999988, + "candidateNs": 15225.858750000041 + }, + { + "baselineNs": 20760.0350000007, + "candidateNs": 15102.218124999352 + }, + { + "baselineNs": 20184.215624999524, + "candidateNs": 20975.447499999973 + }, + { + "baselineNs": 21078.974999999216, + "candidateNs": 27325.152500000062 + }, + { + "baselineNs": 20828.626875000962, + "candidateNs": 15465.336250000519 + }, + { + "baselineNs": 21495.380624999143, + "candidateNs": 15212.332499999093 + }, + { + "baselineNs": 24604.242500000735, + "candidateNs": 20947.413750000123 + }, + { + "baselineNs": 22016.308749999782, + "candidateNs": 20784.436874999985 + }, + { + "baselineNs": 22497.418125000197, + "candidateNs": 16730.84000000017 + }, + { + "baselineNs": 23028.82812500002, + "candidateNs": 21759.46062499975 + }, + { + "baselineNs": 28020.641875000365, + "candidateNs": 28204.87749999984 + }, + { + "baselineNs": 19847.403750000012, + "candidateNs": 17742.645624999794 + }, + { + "baselineNs": 19867.44812500092, + "candidateNs": 15703.586250000399 + }, + { + "baselineNs": 20820.310624999365, + "candidateNs": 15638.249999999516 + }, + { + "baselineNs": 21162.050000000363, + "candidateNs": 15027.996874999872 + }, + { + "baselineNs": 21257.706874999938, + "candidateNs": 15042.368124999257 + }, + { + "baselineNs": 21268.908750000715, + "candidateNs": 15271.187499999995 + }, + { + "baselineNs": 21446.03062500096, + "candidateNs": 15539.138125000136 + }, + { + "baselineNs": 29655.70687500076, + "candidateNs": 24617.467499999748 + }, + { + "baselineNs": 24181.02999999974, + "candidateNs": 15222.752499998933 + }, + { + "baselineNs": 24174.33624999944, + "candidateNs": 16697.570624999116 + }, + { + "baselineNs": 21157.229374999813, + "candidateNs": 15972.50062500052 + }, + { + "baselineNs": 19871.875000000047, + "candidateNs": 15485.079375000623 + } + ] + }, + { + "mode": "prepared", + "name": "custom scalar list", + "count": 3200, + "baselineNs": 12562.147187500159, + "candidateNs": 11697.77593750041, + "ratio": 0.9771056287453004, + "samples": [ + { + "baselineNs": 16881.29281249985, + "candidateNs": 17092.47000000005 + }, + { + "baselineNs": 15612.545624999826, + "candidateNs": 12530.336874999648 + }, + { + "baselineNs": 18303.21093750001, + "candidateNs": 17302.5921874995 + }, + { + "baselineNs": 12956.673749999936, + "candidateNs": 12143.530937499918 + }, + { + "baselineNs": 11887.982499999907, + "candidateNs": 12365.262499999972 + }, + { + "baselineNs": 15013.804687499714, + "candidateNs": 11492.751249999741 + }, + { + "baselineNs": 14586.008750000019, + "candidateNs": 11436.232187500082 + }, + { + "baselineNs": 11767.623750000097, + "candidateNs": 11287.322499999846 + }, + { + "baselineNs": 11417.333750000013, + "candidateNs": 11275.615937499879 + }, + { + "baselineNs": 11450.96281250005, + "candidateNs": 11440.956562499876 + }, + { + "baselineNs": 11412.978749999638, + "candidateNs": 11567.96218750003 + }, + { + "baselineNs": 11925.093125000216, + "candidateNs": 11535.688437500085 + }, + { + "baselineNs": 15404.790312499586, + "candidateNs": 16240.607187500018 + }, + { + "baselineNs": 13510.401249999972, + "candidateNs": 12039.371562499924 + }, + { + "baselineNs": 12562.147187500159, + "candidateNs": 12505.624687499901 + }, + { + "baselineNs": 15173.014687500201, + "candidateNs": 11963.80999999974 + }, + { + "baselineNs": 17733.174374999977, + "candidateNs": 17260.39656250009 + }, + { + "baselineNs": 17526.712499999918, + "candidateNs": 18661.125000000422 + }, + { + "baselineNs": 14729.266874999781, + "candidateNs": 12021.021249999534 + }, + { + "baselineNs": 12276.094062499966, + "candidateNs": 12062.706562500125 + }, + { + "baselineNs": 11218.774062500075, + "candidateNs": 11413.147500000492 + }, + { + "baselineNs": 11370.272812499707, + "candidateNs": 11697.77593750041 + }, + { + "baselineNs": 11998.046562499667, + "candidateNs": 11490.262187500093 + }, + { + "baselineNs": 14933.117812499859, + "candidateNs": 11382.809062500883 + }, + { + "baselineNs": 14374.837812499662, + "candidateNs": 11342.695937499911 + }, + { + "baselineNs": 11475.255937500606, + "candidateNs": 11233.583437500556 + }, + { + "baselineNs": 11390.104062500086, + "candidateNs": 11608.022187499499 + }, + { + "baselineNs": 11405.367500000237, + "candidateNs": 11593.920312500359 + }, + { + "baselineNs": 11743.675312499136, + "candidateNs": 11474.81125000013 + }, + { + "baselineNs": 11790.028437500268, + "candidateNs": 12044.15562500003 + }, + { + "baselineNs": 15054.024375000381, + "candidateNs": 14338.61312499971 + } + ] + }, + { + "mode": "prepared", + "name": "opaque JSON list", + "count": 204800, + "baselineNs": 453.7815917968757, + "candidateNs": 150.1775781250103, + "ratio": 0.3315833786878028, + "samples": [ + { + "baselineNs": 452.55945800782627, + "candidateNs": 150.51562011718644 + }, + { + "baselineNs": 518.677856445322, + "candidateNs": 153.7096435546914 + }, + { + "baselineNs": 445.0161035156164, + "candidateNs": 150.1775781250103 + }, + { + "baselineNs": 442.2883398437527, + "candidateNs": 153.89157714842838 + }, + { + "baselineNs": 444.2954541015531, + "candidateNs": 149.6462011718691 + }, + { + "baselineNs": 516.1865234375007, + "candidateNs": 141.70761718750313 + }, + { + "baselineNs": 448.1833691406223, + "candidateNs": 144.64221679686418 + }, + { + "baselineNs": 459.2237158203183, + "candidateNs": 147.91617187499995 + }, + { + "baselineNs": 456.26651367186355, + "candidateNs": 148.29520996093137 + }, + { + "baselineNs": 511.9599365234429, + "candidateNs": 147.8623144531177 + }, + { + "baselineNs": 453.7815917968757, + "candidateNs": 147.59413085936757 + }, + { + "baselineNs": 447.130986328137, + "candidateNs": 148.21229492188337 + }, + { + "baselineNs": 449.7703027343824, + "candidateNs": 149.54161132813226 + }, + { + "baselineNs": 510.3443847656131, + "candidateNs": 152.52116699219442 + }, + { + "baselineNs": 449.2248828124978, + "candidateNs": 160.91480957031834 + }, + { + "baselineNs": 525.2454394531192, + "candidateNs": 188.54587890626107 + }, + { + "baselineNs": 522.3197460937535, + "candidateNs": 174.7894189453092 + }, + { + "baselineNs": 579.4645410156285, + "candidateNs": 226.95003906250125 + }, + { + "baselineNs": 523.0420556640603, + "candidateNs": 192.31662597656296 + }, + { + "baselineNs": 535.0109619140575, + "candidateNs": 160.61160156251475 + }, + { + "baselineNs": 509.00253906251083, + "candidateNs": 172.4769384765601 + }, + { + "baselineNs": 490.4406591796828, + "candidateNs": 149.83444824219205 + }, + { + "baselineNs": 446.45265624998484, + "candidateNs": 148.20211425780272 + }, + { + "baselineNs": 449.01408691405464, + "candidateNs": 153.78341308593946 + }, + { + "baselineNs": 520.7912207031385, + "candidateNs": 149.05788085938454 + }, + { + "baselineNs": 448.2649658203108, + "candidateNs": 148.6372119140711 + }, + { + "baselineNs": 449.00009277343503, + "candidateNs": 147.7928955078056 + }, + { + "baselineNs": 449.78248535157303, + "candidateNs": 151.11440429688372 + }, + { + "baselineNs": 516.1109912109474, + "candidateNs": 150.75816406248777 + }, + { + "baselineNs": 452.1954931640515, + "candidateNs": 143.58312988282051 + }, + { + "baselineNs": 451.56920410155624, + "candidateNs": 154.2918457031206 + } + ] + }, + { + "mode": "prepared", + "name": "recursive inputs", + "count": 1600, + "baselineNs": 16658.239999999296, + "candidateNs": 14884.5762499991, + "ratio": 0.8893198241028453, + "samples": [ + { + "baselineNs": 16436.871875000634, + "candidateNs": 21028.798749998714 + }, + { + "baselineNs": 16804.923750000853, + "candidateNs": 23802.214375000403 + }, + { + "baselineNs": 16233.94499999904, + "candidateNs": 14689.657500000521 + }, + { + "baselineNs": 16380.315000001247, + "candidateNs": 16722.486874998594 + }, + { + "baselineNs": 16407.59750000143, + "candidateNs": 15206.146250000074 + }, + { + "baselineNs": 16327.916249999817, + "candidateNs": 14860.899999998765 + }, + { + "baselineNs": 16647.83937500033, + "candidateNs": 14809.885000001941 + }, + { + "baselineNs": 16569.904999998926, + "candidateNs": 14735.944999999901 + }, + { + "baselineNs": 16912.99625000056, + "candidateNs": 14802.345624998452 + }, + { + "baselineNs": 16560.380625001017, + "candidateNs": 14567.783124998641 + }, + { + "baselineNs": 24449.93187500131, + "candidateNs": 21363.143124999624 + }, + { + "baselineNs": 16488.68875000062, + "candidateNs": 14502.76062500052 + }, + { + "baselineNs": 16658.239999999296, + "candidateNs": 14635.204999999587 + }, + { + "baselineNs": 16543.022500000006, + "candidateNs": 14884.5762499991 + }, + { + "baselineNs": 16459.983749998628, + "candidateNs": 14558.647500000461 + }, + { + "baselineNs": 17080.343749998974, + "candidateNs": 14468.051874998764 + }, + { + "baselineNs": 17039.09062500088, + "candidateNs": 14628.85500000084 + }, + { + "baselineNs": 16625.509375001002, + "candidateNs": 14766.077500000847 + }, + { + "baselineNs": 16614.357500000096, + "candidateNs": 14744.836875001965 + }, + { + "baselineNs": 23301.167499998883, + "candidateNs": 14738.05562500047 + }, + { + "baselineNs": 24263.96187499904, + "candidateNs": 15031.72312499828 + }, + { + "baselineNs": 16700.96437500206, + "candidateNs": 14925.948125001016 + }, + { + "baselineNs": 17312.71437500027, + "candidateNs": 15064.58500000008 + }, + { + "baselineNs": 16936.616250000043, + "candidateNs": 15007.020000000466 + }, + { + "baselineNs": 16516.87875000107, + "candidateNs": 14909.485624998524 + }, + { + "baselineNs": 16909.46500000109, + "candidateNs": 15449.725625001063 + }, + { + "baselineNs": 16645.12187499895, + "candidateNs": 15170.071874999849 + }, + { + "baselineNs": 22187.563750001118, + "candidateNs": 20489.116875000946 + }, + { + "baselineNs": 25374.68562499953, + "candidateNs": 23534.834375000173 + }, + { + "baselineNs": 17893.743125000583, + "candidateNs": 18115.894374998334 + }, + { + "baselineNs": 16722.787500000322, + "candidateNs": 14772.194999998192 + } + ] + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/paired-summary.json b/packages/rescript-relay/benchmarks/results/js-specialization/paired-summary.json new file mode 100644 index 00000000..f6fff92c --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/paired-summary.json @@ -0,0 +1,210 @@ +[ + { + "fixtureVersion": 3, + "node": "v24.16.0", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "cpuAffinity": "7", + "samples": 31, + "targetSampleMs": 20, + "initialLoad": [ + 22.3, + 18.93, + 19.82 + ], + "finalLoad": [ + 18.66, + 18.35, + 19.61 + ], + "implementations": { + "baseline": "/tmp/relay-js-sweep/baseline/utils.js", + "candidate": "/tmp/rescript-relay-conversion-perf/packages/rescript-relay/src/utils.js" + }, + "sha256": { + "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", + "candidate": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedCandidate": "db39247dc78284162c7fe25551523d1681c4e469d37fceb7e24912b542a2e5c9", + "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" + }, + "results": [ + { + "mode": "prepared", + "name": "small fragment", + "count": 409600, + "baselineNs": 133.1544189453124, + "candidateNs": 107.24046142578158, + "ratio": 0.9096685277863316 + }, + { + "mode": "prepared", + "name": "unchanged object", + "count": 819200, + "baselineNs": 58.568532714844416, + "candidateNs": 50.305067138671774, + "ratio": 0.8502233170869574 + }, + { + "mode": "prepared", + "name": "nullable query", + "count": 204800, + "baselineNs": 153.67666503906196, + "candidateNs": 123.89265136718565, + "ratio": 0.8094886849135811 + }, + { + "mode": "prepared", + "name": "connection / 100 rows", + "count": 1600, + "baselineNs": 20544.051250000164, + "candidateNs": 16301.078125000005, + "ratio": 0.8018581403398429 + }, + { + "mode": "prepared", + "name": "plural fragment / 100 rows", + "count": 3200, + "baselineNs": 14444.88906250001, + "candidateNs": 12310.415312499572, + "ratio": 0.8546198603466574 + }, + { + "mode": "prepared", + "name": "union list / 100 rows", + "count": 1600, + "baselineNs": 17610.5831250004, + "candidateNs": 14483.900000000176, + "ratio": 0.8229835643663055 + }, + { + "mode": "prepared", + "name": "custom scalar list", + "count": 3200, + "baselineNs": 11502.360000000068, + "candidateNs": 11730.23124999986, + "ratio": 0.9985159326394925 + }, + { + "mode": "prepared", + "name": "opaque JSON list", + "count": 204800, + "baselineNs": 457.5926562499966, + "candidateNs": 152.5702294921949, + "ratio": 0.33681605845024465 + }, + { + "mode": "prepared", + "name": "recursive inputs", + "count": 1600, + "baselineNs": 15661.099999999808, + "candidateNs": 14689.069375001509, + "ratio": 0.9428667930457257 + } + ], + "run": 1 + }, + { + "fixtureVersion": 3, + "node": "v24.16.0", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "cpuAffinity": "7", + "samples": 31, + "targetSampleMs": 20, + "initialLoad": [ + 18.66, + 18.35, + 19.61 + ], + "finalLoad": [ + 18.51, + 18.31, + 19.56 + ], + "implementations": { + "baseline": "/tmp/relay-js-sweep/baseline/utils.js", + "candidate": "/tmp/rescript-relay-conversion-perf/packages/rescript-relay/src/utils.js" + }, + "sha256": { + "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", + "candidate": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", + "preparedCandidate": "db39247dc78284162c7fe25551523d1681c4e469d37fceb7e24912b542a2e5c9", + "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" + }, + "results": [ + { + "mode": "prepared", + "name": "small fragment", + "count": 409600, + "baselineNs": 101.97609375000027, + "candidateNs": 93.63988037109361, + "ratio": 0.911205684427288 + }, + { + "mode": "prepared", + "name": "unchanged object", + "count": 819200, + "baselineNs": 57.85585937500004, + "candidateNs": 49.18847900390655, + "ratio": 0.8518584576886907 + }, + { + "mode": "prepared", + "name": "nullable query", + "count": 102400, + "baselineNs": 150.39659179687524, + "candidateNs": 121.40841796874469, + "ratio": 0.8109976437073325 + }, + { + "mode": "prepared", + "name": "connection / 100 rows", + "count": 1600, + "baselineNs": 20627.377499999966, + "candidateNs": 16061.450000000263, + "ratio": 0.7978602752308714 + }, + { + "mode": "prepared", + "name": "plural fragment / 100 rows", + "count": 3200, + "baselineNs": 14628.395000000295, + "candidateNs": 12268.573437499981, + "ratio": 0.8496155826051577 + }, + { + "mode": "prepared", + "name": "union list / 100 rows", + "count": 1600, + "baselineNs": 21162.050000000363, + "candidateNs": 15568.825624999363, + "ratio": 0.749143054513265 + }, + { + "mode": "prepared", + "name": "custom scalar list", + "count": 3200, + "baselineNs": 12562.147187500159, + "candidateNs": 11697.77593750041, + "ratio": 0.9771056287453004 + }, + { + "mode": "prepared", + "name": "opaque JSON list", + "count": 204800, + "baselineNs": 453.7815917968757, + "candidateNs": 150.1775781250103, + "ratio": 0.3315833786878028 + }, + { + "mode": "prepared", + "name": "recursive inputs", + "count": 1600, + "baselineNs": 16658.239999999296, + "candidateNs": 14884.5762499991, + "ratio": 0.8893198241028453 + } + ], + "run": 2 + } +] diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/runtime-size-esm.json b/packages/rescript-relay/benchmarks/results/js-specialization/runtime-size-esm.json new file mode 100644 index 00000000..70315233 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/runtime-size-esm.json @@ -0,0 +1,15 @@ +{ + "esbuild": "0.25.12", + "results": { + "before": { + "minified": 5578, + "gzip": 2238, + "brotli": 2032 + }, + "after": { + "minified": 5847, + "gzip": 2320, + "brotli": 2101 + } + } +} diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/runtime-size.json b/packages/rescript-relay/benchmarks/results/js-specialization/runtime-size.json new file mode 100644 index 00000000..032bab0a --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/runtime-size.json @@ -0,0 +1,15 @@ +{ + "esbuild": "0.25.12", + "results": { + "before": { + "minified": 5786, + "gzip": 2330, + "brotli": 2108 + }, + "after": { + "minified": 6056, + "gzip": 2409, + "brotli": 2178 + } + } +} diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/standalone-after.json b/packages/rescript-relay/benchmarks/results/js-specialization/standalone-after.json new file mode 100644 index 00000000..9585ed74 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/standalone-after.json @@ -0,0 +1,670 @@ +{ + "fixtureVersion": 3, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "cpuTiming": "thread", + "implementation": "src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 819200, + "newOutputObjects": 3, + "preparationNs": 5949.421999999998, + "medianNs": 95.10610595703115, + "medianCpuNs": 95.189208984375, + "cpuSamples": [ + { + "wallNs": 91.39721801757808, + "cpuNs": 91.50634765625 + }, + { + "wallNs": 102.88083129882808, + "cpuNs": 102.509765625 + }, + { + "wallNs": 102.97089355468754, + "cpuNs": 103.714599609375 + }, + { + "wallNs": 87.85980834960947, + "cpuNs": 87.8662109375 + }, + { + "wallNs": 95.10610595703115, + "cpuNs": 95.189208984375 + }, + { + "wallNs": 86.03745483398443, + "cpuNs": 85.426025390625 + }, + { + "wallNs": 91.04812011718755, + "cpuNs": 91.53076171875 + }, + { + "wallNs": 127.2467578125, + "cpuNs": 126.90185546875 + }, + { + "wallNs": 118.41307373046881, + "cpuNs": 118.372802734375 + }, + { + "wallNs": 166.60675292968747, + "cpuNs": 167.203369140625 + }, + { + "wallNs": 124.94414062499987, + "cpuNs": 124.47021484375 + }, + { + "wallNs": 86.66969238281251, + "cpuNs": 86.63818359375 + }, + { + "wallNs": 87.64365234375016, + "cpuNs": 87.867431640625 + }, + { + "wallNs": 116.43067871093758, + "cpuNs": 115.931396484375 + }, + { + "wallNs": 92.27530395507806, + "cpuNs": 92.750244140625 + } + ], + "p10Ns": 86.66969238281251, + "p90Ns": 127.2467578125, + "opsPerSecond": 10514572.013407836 + }, + { + "name": "unchanged object", + "iterations": 1638400, + "newOutputObjects": 0, + "preparationNs": 0, + "medianNs": 47.22500976562502, + "medianCpuNs": 46.9970703125, + "cpuSamples": [ + { + "wallNs": 46.02683532714841, + "cpuNs": 45.7696533203125 + }, + { + "wallNs": 46.664110717773426, + "cpuNs": 46.38671875 + }, + { + "wallNs": 62.069307250976614, + "cpuNs": 62.2369384765625 + }, + { + "wallNs": 49.25921264648442, + "cpuNs": 49.4384765625 + }, + { + "wallNs": 47.22500976562502, + "cpuNs": 46.9970703125 + }, + { + "wallNs": 51.43985900878917, + "cpuNs": 51.8682861328125 + }, + { + "wallNs": 49.060185546875026, + "cpuNs": 48.8238525390625 + }, + { + "wallNs": 46.39650939941398, + "cpuNs": 46.37939453125 + }, + { + "wallNs": 59.808210449218684, + "cpuNs": 59.814453125 + }, + { + "wallNs": 46.75909057617195, + "cpuNs": 46.9964599609375 + }, + { + "wallNs": 47.758562011718524, + "cpuNs": 47.6068115234375 + }, + { + "wallNs": 45.912666625976534, + "cpuNs": 45.767822265625 + }, + { + "wallNs": 46.489287109375, + "cpuNs": 46.3836669921875 + }, + { + "wallNs": 46.224210815429544, + "cpuNs": 46.38671875 + }, + { + "wallNs": 60.61259338378893, + "cpuNs": 60.418701171875 + } + ], + "p10Ns": 46.02683532714841, + "p90Ns": 60.61259338378893, + "opsPerSecond": 21175220.60795629 + }, + { + "name": "nullable query", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 0, + "medianNs": 115.87322753906281, + "medianCpuNs": 117.13134765625, + "cpuSamples": [ + { + "wallNs": 119.68656005859391, + "cpuNs": 119.57275390625 + }, + { + "wallNs": 116.14207031250045, + "cpuNs": 117.1142578125 + }, + { + "wallNs": 115.87322753906281, + "cpuNs": 114.66796875 + }, + { + "wallNs": 119.18338867187516, + "cpuNs": 119.560546875 + }, + { + "wallNs": 115.5820532226559, + "cpuNs": 117.158203125 + }, + { + "wallNs": 115.3517822265626, + "cpuNs": 114.67529296875 + }, + { + "wallNs": 222.09853759765585, + "cpuNs": 222.099609375 + }, + { + "wallNs": 157.1183764648443, + "cpuNs": 156.14990234375 + }, + { + "wallNs": 115.83614746093707, + "cpuNs": 117.13623046875 + }, + { + "wallNs": 115.13019775390654, + "cpuNs": 114.70458984375 + }, + { + "wallNs": 116.91423339843743, + "cpuNs": 117.13134765625 + }, + { + "wallNs": 115.06711425781192, + "cpuNs": 114.6484375 + }, + { + "wallNs": 118.86388671874971, + "cpuNs": 119.57763671875 + }, + { + "wallNs": 115.5432592773442, + "cpuNs": 114.67529296875 + }, + { + "wallNs": 115.74750244140674, + "cpuNs": 114.69970703125 + } + ], + "p10Ns": 115.13019775390654, + "p90Ns": 157.1183764648443, + "opsPerSecond": 8630121.221598692 + }, + { + "name": "connection / 100 rows", + "iterations": 3200, + "newOutputObjects": 403, + "preparationNs": 5694.891000000098, + "medianNs": 15765.46250000007, + "medianCpuNs": 15586.25, + "cpuSamples": [ + { + "wallNs": 17901.758750000026, + "cpuNs": 18070 + }, + { + "wallNs": 21025.360937499896, + "cpuNs": 20560 + }, + { + "wallNs": 19115.433437500116, + "cpuNs": 18952.8125 + }, + { + "wallNs": 15449.938125000244, + "cpuNs": 15575.3125 + }, + { + "wallNs": 15476.507187500203, + "cpuNs": 15457.5 + }, + { + "wallNs": 15995.146250000118, + "cpuNs": 15707.5 + }, + { + "wallNs": 15215.81124999983, + "cpuNs": 15269.6875 + }, + { + "wallNs": 22682.1884375002, + "cpuNs": 22757.5 + }, + { + "wallNs": 15656.099374999998, + "cpuNs": 15579.6875 + }, + { + "wallNs": 15302.963437499953, + "cpuNs": 15277.1875 + }, + { + "wallNs": 15765.46250000007, + "cpuNs": 15586.25 + }, + { + "wallNs": 17238.326874999926, + "cpuNs": 17140 + }, + { + "wallNs": 15338.624687499874, + "cpuNs": 15583.4375 + }, + { + "wallNs": 15865.160312499995, + "cpuNs": 15830.625 + }, + { + "wallNs": 15591.223750000154, + "cpuNs": 15329.375 + } + ], + "p10Ns": 15302.963437499953, + "p90Ns": 21025.360937499896, + "opsPerSecond": 63429.791545918524 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 6400, + "newOutputObjects": 301, + "preparationNs": 1207.331999999951, + "medianNs": 12846.041250000015, + "medianCpuNs": 12836.09375, + "cpuSamples": [ + { + "wallNs": 12379.555156250035, + "cpuNs": 12311.875 + }, + { + "wallNs": 12846.041250000015, + "cpuNs": 12874.21875 + }, + { + "wallNs": 12916.93140625, + "cpuNs": 12836.09375 + }, + { + "wallNs": 14356.345156249972, + "cpuNs": 14337.8125 + }, + { + "wallNs": 14429.54125, + "cpuNs": 14335.625 + }, + { + "wallNs": 16713.045156249962, + "cpuNs": 16677.5 + }, + { + "wallNs": 12211.506249999928, + "cpuNs": 12324.6875 + }, + { + "wallNs": 12052.627968750045, + "cpuNs": 12013.90625 + }, + { + "wallNs": 12002.675781250076, + "cpuNs": 12010.625 + }, + { + "wallNs": 12236.741406250074, + "cpuNs": 12169.0625 + }, + { + "wallNs": 16317.635624999979, + "cpuNs": 16223.28125 + }, + { + "wallNs": 18144.185468750038, + "cpuNs": 18099.84375 + }, + { + "wallNs": 12126.77421875, + "cpuNs": 12165.3125 + }, + { + "wallNs": 12177.232187499954, + "cpuNs": 12166.875 + }, + { + "wallNs": 19870.90609375002, + "cpuNs": 19815.15625 + } + ], + "p10Ns": 12052.627968750045, + "p90Ns": 18144.185468750038, + "opsPerSecond": 77844.99368628439 + }, + { + "name": "union list / 100 rows", + "iterations": 3200, + "newOutputObjects": 302, + "preparationNs": 5832.9219999995985, + "medianNs": 30800.429062500145, + "medianCpuNs": 30579.375, + "cpuSamples": [ + { + "wallNs": 30800.429062500145, + "cpuNs": 30583.75 + }, + { + "wallNs": 30348.572187500056, + "cpuNs": 30576.5625 + }, + { + "wallNs": 30433.231874999936, + "cpuNs": 30260.3125 + }, + { + "wallNs": 30136.900312500075, + "cpuNs": 29951.875 + }, + { + "wallNs": 30332.607500000107, + "cpuNs": 30264.0625 + }, + { + "wallNs": 30355.131249999944, + "cpuNs": 30579.375 + }, + { + "wallNs": 30488.749375000167, + "cpuNs": 30260.625 + }, + { + "wallNs": 30822.661874999823, + "cpuNs": 30891.25 + }, + { + "wallNs": 31028.77937500011, + "cpuNs": 30893.4375 + }, + { + "wallNs": 30892.875625000048, + "cpuNs": 30887.1875 + }, + { + "wallNs": 31476.080937499944, + "cpuNs": 31517.5 + }, + { + "wallNs": 31222.063437500085, + "cpuNs": 31206.5625 + }, + { + "wallNs": 31505.649062499968, + "cpuNs": 31518.125 + }, + { + "wallNs": 30807.210312500218, + "cpuNs": 30574.0625 + }, + { + "wallNs": 30600.23812499992, + "cpuNs": 30571.875 + } + ], + "p10Ns": 30332.607500000107, + "p90Ns": 31476.080937499944, + "opsPerSecond": 32467.080181604055 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "preparationNs": 4275.648999999248, + "medianNs": 21663.08500000014, + "medianCpuNs": 21547.8125, + "cpuSamples": [ + { + "wallNs": 21822.62687500014, + "cpuNs": 21835.9375 + }, + { + "wallNs": 21545.94156249999, + "cpuNs": 21545.625 + }, + { + "wallNs": 21412.536562500292, + "cpuNs": 21229.375 + }, + { + "wallNs": 21524.992812500157, + "cpuNs": 21542.5 + }, + { + "wallNs": 21399.34593750013, + "cpuNs": 21503.125 + }, + { + "wallNs": 21663.08500000014, + "cpuNs": 21419.375 + }, + { + "wallNs": 21585.315937500127, + "cpuNs": 21546.25 + }, + { + "wallNs": 21584.91187499976, + "cpuNs": 21546.875 + }, + { + "wallNs": 21759.98687499998, + "cpuNs": 21858.4375 + }, + { + "wallNs": 22043.59124999996, + "cpuNs": 21866.5625 + }, + { + "wallNs": 22210.816875000317, + "cpuNs": 22165.625 + }, + { + "wallNs": 22080.398437499865, + "cpuNs": 22168.4375 + }, + { + "wallNs": 22160.38718749985, + "cpuNs": 22172.8125 + }, + { + "wallNs": 22125.026562500236, + "cpuNs": 22172.1875 + }, + { + "wallNs": 21589.379999999775, + "cpuNs": 21547.8125 + } + ], + "p10Ns": 21412.536562500292, + "p90Ns": 22160.38718749985, + "opsPerSecond": 46161.477001082414 + }, + { + "name": "opaque JSON list", + "iterations": 409600, + "newOutputObjects": 0, + "preparationNs": 3253.177999999025, + "medianNs": 220.89814941406158, + "medianCpuNs": 222.0654296875, + "cpuSamples": [ + { + "wallNs": 157.09154541015735, + "cpuNs": 158.68896484375 + }, + { + "wallNs": 159.77429931640864, + "cpuNs": 158.68896484375 + }, + { + "wallNs": 187.8418627929701, + "cpuNs": 182.6806640625 + }, + { + "wallNs": 157.0997607421898, + "cpuNs": 156.25 + }, + { + "wallNs": 158.20108642578214, + "cpuNs": 158.68896484375 + }, + { + "wallNs": 194.64226074218604, + "cpuNs": 195.3125 + }, + { + "wallNs": 228.90872070312707, + "cpuNs": 229.462890625 + }, + { + "wallNs": 226.4634497070306, + "cpuNs": 227.00439453125 + }, + { + "wallNs": 223.1860913085937, + "cpuNs": 222.0654296875 + }, + { + "wallNs": 224.61572265624952, + "cpuNs": 224.609375 + }, + { + "wallNs": 220.71117675781517, + "cpuNs": 219.6728515625 + }, + { + "wallNs": 220.89814941406158, + "cpuNs": 222.16552734375 + }, + { + "wallNs": 224.30262939453272, + "cpuNs": 224.5947265625 + }, + { + "wallNs": 223.057966308593, + "cpuNs": 222.13623046875 + }, + { + "wallNs": 223.35139404296987, + "cpuNs": 224.58251953125 + } + ], + "p10Ns": 157.0997607421898, + "p90Ns": 226.4634497070306, + "opsPerSecond": 4526973.189465496 + }, + { + "name": "recursive inputs", + "iterations": 3200, + "newOutputObjects": 103, + "preparationNs": 5699.339000000691, + "medianNs": 31886.305937500194, + "medianCpuNs": 31849.0625, + "cpuSamples": [ + { + "wallNs": 15432.214062500407, + "cpuNs": 15488.4375 + }, + { + "wallNs": 15597.576562499853, + "cpuNs": 15359.0625 + }, + { + "wallNs": 15467.643437499986, + "cpuNs": 15607.5 + }, + { + "wallNs": 25675.920937499657, + "cpuNs": 25591.5625 + }, + { + "wallNs": 32154.781874999684, + "cpuNs": 32164.6875 + }, + { + "wallNs": 31995.070937500146, + "cpuNs": 31851.5625 + }, + { + "wallNs": 31886.305937500194, + "cpuNs": 31865.9375 + }, + { + "wallNs": 31936.529062500085, + "cpuNs": 31849.0625 + }, + { + "wallNs": 32218.85312500035, + "cpuNs": 32162.5 + }, + { + "wallNs": 32268.133437499953, + "cpuNs": 32164.6875 + }, + { + "wallNs": 32171.450937500478, + "cpuNs": 32161.5625 + }, + { + "wallNs": 32284.257812499956, + "cpuNs": 32165.3125 + }, + { + "wallNs": 22717.542812499687, + "cpuNs": 22787.8125 + }, + { + "wallNs": 16489.073750000218, + "cpuNs": 15457.5 + }, + { + "wallNs": 15698.952187499914, + "cpuNs": 15914.375 + } + ], + "p10Ns": 15467.643437499986, + "p90Ns": 32268.133437499953, + "opsPerSecond": 31361.42524505921 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/standalone-before.json b/packages/rescript-relay/benchmarks/results/js-specialization/standalone-before.json new file mode 100644 index 00000000..4bd9e261 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/standalone-before.json @@ -0,0 +1,670 @@ +{ + "fixtureVersion": 3, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 15, + "durationMs": 40, + "cpuTiming": "thread", + "implementation": "/tmp/relay-js-sweep/baseline/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 7002.310999999999, + "medianNs": 100.9031176757813, + "medianCpuNs": 100.0634765625, + "cpuSamples": [ + { + "wallNs": 100.17481445312497, + "cpuNs": 100.0634765625 + }, + { + "wallNs": 99.9192041015625, + "cpuNs": 100.0390625 + }, + { + "wallNs": 100.9031176757813, + "cpuNs": 100.01220703125 + }, + { + "wallNs": 102.31249511718748, + "cpuNs": 102.49755859375 + }, + { + "wallNs": 187.80910888671883, + "cpuNs": 187.88818359375 + }, + { + "wallNs": 143.3190356445313, + "cpuNs": 143.94775390625 + }, + { + "wallNs": 98.3079565429687, + "cpuNs": 97.6025390625 + }, + { + "wallNs": 97.4653002929686, + "cpuNs": 97.61474609375 + }, + { + "wallNs": 206.51361816406254, + "cpuNs": 124.75341796875 + }, + { + "wallNs": 96.48194580078123, + "cpuNs": 95.166015625 + }, + { + "wallNs": 101.0023291015627, + "cpuNs": 100.0634765625 + }, + { + "wallNs": 97.71158935546892, + "cpuNs": 97.60498046875 + }, + { + "wallNs": 97.98104492187514, + "cpuNs": 97.60498046875 + }, + { + "wallNs": 103.14610107421879, + "cpuNs": 102.5 + }, + { + "wallNs": 116.14500732421874, + "cpuNs": 117.12890625 + } + ], + "p10Ns": 97.4653002929686, + "p90Ns": 187.80910888671883, + "opsPerSecond": 9910496.553864354 + }, + { + "name": "unchanged object", + "iterations": 819200, + "newOutputObjects": 0, + "preparationNs": 0, + "medianNs": 69.9711596679689, + "medianCpuNs": 69.580078125, + "cpuSamples": [ + { + "wallNs": 60.792462158203165, + "cpuNs": 61.00341796875 + }, + { + "wallNs": 84.81014892578132, + "cpuNs": 84.228515625 + }, + { + "wallNs": 52.806717529296776, + "cpuNs": 53.7109375 + }, + { + "wallNs": 53.400614013671685, + "cpuNs": 52.489013671875 + }, + { + "wallNs": 70.32150268554693, + "cpuNs": 70.7861328125 + }, + { + "wallNs": 53.33789672851558, + "cpuNs": 53.712158203125 + }, + { + "wallNs": 71.59639770507792, + "cpuNs": 70.694580078125 + }, + { + "wallNs": 65.36670532226563, + "cpuNs": 65.91064453125 + }, + { + "wallNs": 57.56339843750013, + "cpuNs": 57.364501953125 + }, + { + "wallNs": 69.9711596679689, + "cpuNs": 70.80078125 + }, + { + "wallNs": 70.57305297851562, + "cpuNs": 69.580078125 + }, + { + "wallNs": 70.86381225585941, + "cpuNs": 70.787353515625 + }, + { + "wallNs": 69.97182006835939, + "cpuNs": 70.799560546875 + }, + { + "wallNs": 52.875426025390524, + "cpuNs": 52.490234375 + }, + { + "wallNs": 71.01458618164081, + "cpuNs": 70.802001953125 + } + ], + "p10Ns": 52.875426025390524, + "p90Ns": 71.59639770507792, + "opsPerSecond": 14291602.49373108 + }, + { + "name": "nullable query", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 0, + "medianNs": 182.95464843749997, + "medianCpuNs": 183.02734375, + "cpuSamples": [ + { + "wallNs": 183.9224462890626, + "cpuNs": 185.4541015625 + }, + { + "wallNs": 209.4647021484369, + "cpuNs": 209.76806640625 + }, + { + "wallNs": 147.12913818359374, + "cpuNs": 146.44775390625 + }, + { + "wallNs": 148.01995849609395, + "cpuNs": 148.876953125 + }, + { + "wallNs": 149.02874999999983, + "cpuNs": 148.84033203125 + }, + { + "wallNs": 187.51871826171885, + "cpuNs": 185.45166015625 + }, + { + "wallNs": 187.11448730468706, + "cpuNs": 187.94677734375 + }, + { + "wallNs": 182.95464843749997, + "cpuNs": 183.02734375 + }, + { + "wallNs": 218.54770996093785, + "cpuNs": 219.677734375 + }, + { + "wallNs": 218.20578369140532, + "cpuNs": 217.20703125 + }, + { + "wallNs": 151.02554199218798, + "cpuNs": 151.31591796875 + }, + { + "wallNs": 151.0672460937501, + "cpuNs": 151.2890625 + }, + { + "wallNs": 188.95918457031203, + "cpuNs": 187.92236328125 + }, + { + "wallNs": 158.67290283203107, + "cpuNs": 158.64013671875 + }, + { + "wallNs": 171.3014038085936, + "cpuNs": 170.80810546875 + } + ], + "p10Ns": 148.01995849609395, + "p90Ns": 218.20578369140532, + "opsPerSecond": 5465835.432662509 + }, + { + "name": "connection / 100 rows", + "iterations": 3200, + "newOutputObjects": 403, + "preparationNs": 7229.080000000067, + "medianNs": 20237.900937500086, + "medianCpuNs": 20254.6875, + "cpuSamples": [ + { + "wallNs": 20237.900937500086, + "cpuNs": 20254.6875 + }, + { + "wallNs": 21030.683749999924, + "cpuNs": 20518.4375 + }, + { + "wallNs": 19677.73937499999, + "cpuNs": 19633.125 + }, + { + "wallNs": 20192.674999999977, + "cpuNs": 20248.75 + }, + { + "wallNs": 19516.2628125, + "cpuNs": 19315 + }, + { + "wallNs": 26901.72125000004, + "cpuNs": 26813.125 + }, + { + "wallNs": 19468.885624999926, + "cpuNs": 19645.3125 + }, + { + "wallNs": 19562.44656249993, + "cpuNs": 19332.8125 + }, + { + "wallNs": 20891.943437499947, + "cpuNs": 20894.0625 + }, + { + "wallNs": 19795.85656249995, + "cpuNs": 19956.5625 + }, + { + "wallNs": 19517.114062500128, + "cpuNs": 19325.9375 + }, + { + "wallNs": 21185.42593750007, + "cpuNs": 21201.5625 + }, + { + "wallNs": 25085.808749999924, + "cpuNs": 25040 + }, + { + "wallNs": 26355.498749999955, + "cpuNs": 26393.125 + }, + { + "wallNs": 22910.294687499972, + "cpuNs": 22764.6875 + } + ], + "p10Ns": 19516.2628125, + "p90Ns": 26355.498749999955, + "opsPerSecond": 49412.23909971003 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 3200, + "newOutputObjects": 301, + "preparationNs": 1242.557999999917, + "medianNs": 16496.158749999948, + "medianCpuNs": 16213.125, + "cpuSamples": [ + { + "wallNs": 15143.844062500024, + "cpuNs": 15272.5 + }, + { + "wallNs": 16175.5309374999, + "cpuNs": 15630.9375 + }, + { + "wallNs": 17959.069999999996, + "cpuNs": 17768.75 + }, + { + "wallNs": 24509.291249999875, + "cpuNs": 24639.0625 + }, + { + "wallNs": 18856.784999999833, + "cpuNs": 18696.25 + }, + { + "wallNs": 19582.756874999915, + "cpuNs": 19643.4375 + }, + { + "wallNs": 16208.396562500127, + "cpuNs": 16210.9375 + }, + { + "wallNs": 16496.158749999948, + "cpuNs": 16210.9375 + }, + { + "wallNs": 16212.353749999977, + "cpuNs": 16213.125 + }, + { + "wallNs": 16152.3465625001, + "cpuNs": 16207.8125 + }, + { + "wallNs": 16135.78093749993, + "cpuNs": 16210.3125 + }, + { + "wallNs": 16518.050312500065, + "cpuNs": 16195.625 + }, + { + "wallNs": 21392.094375, + "cpuNs": 21514.375 + }, + { + "wallNs": 19758.113125000138, + "cpuNs": 19655.3125 + }, + { + "wallNs": 16334.637812500148, + "cpuNs": 16222.5 + } + ], + "p10Ns": 16135.78093749993, + "p90Ns": 21392.094375, + "opsPerSecond": 60620.173166071356 + }, + { + "name": "union list / 100 rows", + "iterations": 3200, + "newOutputObjects": 302, + "preparationNs": 6242.906999999833, + "medianNs": 17636.18812499999, + "medianCpuNs": 17470.9375, + "cpuSamples": [ + { + "wallNs": 16934.89718749987, + "cpuNs": 16840.3125 + }, + { + "wallNs": 17296.815625000192, + "cpuNs": 17152.5 + }, + { + "wallNs": 16876.161250000052, + "cpuNs": 16845 + }, + { + "wallNs": 17071.668124999916, + "cpuNs": 17146.5625 + }, + { + "wallNs": 23875.08968750012, + "cpuNs": 23700.625 + }, + { + "wallNs": 17056.733750000036, + "cpuNs": 16845.625 + }, + { + "wallNs": 16854.845937500046, + "cpuNs": 16840.625 + }, + { + "wallNs": 17066.257812500113, + "cpuNs": 17162.1875 + }, + { + "wallNs": 17636.18812499999, + "cpuNs": 17470.9375 + }, + { + "wallNs": 18899.017812499893, + "cpuNs": 19024.6875 + }, + { + "wallNs": 18752.870000000145, + "cpuNs": 18721.25 + }, + { + "wallNs": 18918.050937500084, + "cpuNs": 18725.625 + }, + { + "wallNs": 24665.09812499993, + "cpuNs": 24620.625 + }, + { + "wallNs": 19587.788125000145, + "cpuNs": 19652.1875 + }, + { + "wallNs": 21539.792500000203, + "cpuNs": 21521.25 + } + ], + "p10Ns": 16876.161250000052, + "p90Ns": 23875.08968750012, + "opsPerSecond": 56701.59520369715 + }, + { + "name": "custom scalar list", + "iterations": 6400, + "newOutputObjects": 102, + "preparationNs": 3283.0439999997902, + "medianNs": 11794.435312499872, + "medianCpuNs": 11864.21875, + "cpuSamples": [ + { + "wallNs": 11269.991093749923, + "cpuNs": 11242.96875 + }, + { + "wallNs": 11761.336874999985, + "cpuNs": 11708.59375 + }, + { + "wallNs": 14540.446093750035, + "cpuNs": 14523.90625 + }, + { + "wallNs": 11434.260937499941, + "cpuNs": 11556.71875 + }, + { + "wallNs": 11408.424687500086, + "cpuNs": 11400.3125 + }, + { + "wallNs": 11508.44656249987, + "cpuNs": 11399.0625 + }, + { + "wallNs": 11655.017187499938, + "cpuNs": 11710.625 + }, + { + "wallNs": 11660.784375000048, + "cpuNs": 11554.0625 + }, + { + "wallNs": 17832.357187500063, + "cpuNs": 12919.84375 + }, + { + "wallNs": 11973.019687500111, + "cpuNs": 11864.21875 + }, + { + "wallNs": 11794.435312499872, + "cpuNs": 11868.28125 + }, + { + "wallNs": 12997.612031250013, + "cpuNs": 12959.0625 + }, + { + "wallNs": 11876.73453125001, + "cpuNs": 11866.875 + }, + { + "wallNs": 11826.940625000048, + "cpuNs": 11867.34375 + }, + { + "wallNs": 13264.289374999977, + "cpuNs": 13274.6875 + } + ], + "p10Ns": 11408.424687500086, + "p90Ns": 14540.446093750035, + "opsPerSecond": 84785.74628665681 + }, + { + "name": "opaque JSON list", + "iterations": 102400, + "newOutputObjects": 0, + "preparationNs": 3467.5820000002204, + "medianNs": 443.1474316406181, + "medianCpuNs": 449.169921875, + "cpuSamples": [ + { + "wallNs": 449.1951855468823, + "cpuNs": 449.21875 + }, + { + "wallNs": 447.25460937499406, + "cpuNs": 449.208984375 + }, + { + "wallNs": 449.8569824218723, + "cpuNs": 449.228515625 + }, + { + "wallNs": 454.07648437500114, + "cpuNs": 449.267578125 + }, + { + "wallNs": 441.98831054687025, + "cpuNs": 449.0625 + }, + { + "wallNs": 438.72952148436895, + "cpuNs": 429.677734375 + }, + { + "wallNs": 456.7929492187517, + "cpuNs": 458.88671875 + }, + { + "wallNs": 432.84623046875305, + "cpuNs": 439.443359375 + }, + { + "wallNs": 586.6746093749953, + "cpuNs": 585.64453125 + }, + { + "wallNs": 436.51195312500056, + "cpuNs": 429.697265625 + }, + { + "wallNs": 437.02776367188, + "cpuNs": 439.287109375 + }, + { + "wallNs": 442.2229394531385, + "cpuNs": 449.208984375 + }, + { + "wallNs": 441.343242187493, + "cpuNs": 439.287109375 + }, + { + "wallNs": 443.1474316406181, + "cpuNs": 439.35546875 + }, + { + "wallNs": 446.1407812499907, + "cpuNs": 449.169921875 + } + ], + "p10Ns": 436.51195312500056, + "p90Ns": 456.7929492187517, + "opsPerSecond": 2256585.345192694 + }, + { + "name": "recursive inputs", + "iterations": 3200, + "newOutputObjects": 103, + "preparationNs": 4607.867999999143, + "medianNs": 16817.159062499628, + "medianCpuNs": 16863.125, + "cpuSamples": [ + { + "wallNs": 18069.372187500223, + "cpuNs": 18101.5625 + }, + { + "wallNs": 21393.631875000097, + "cpuNs": 21244.0625 + }, + { + "wallNs": 17263.324062499803, + "cpuNs": 17171.875 + }, + { + "wallNs": 16718.081249999843, + "cpuNs": 16860.625 + }, + { + "wallNs": 16496.603437499856, + "cpuNs": 16547.8125 + }, + { + "wallNs": 16527.840625000183, + "cpuNs": 16547.8125 + }, + { + "wallNs": 16697.06656249957, + "cpuNs": 16548.75 + }, + { + "wallNs": 16475.88312500034, + "cpuNs": 16549.375 + }, + { + "wallNs": 16530.379687499706, + "cpuNs": 16549.6875 + }, + { + "wallNs": 30263.141874999634, + "cpuNs": 18477.1875 + }, + { + "wallNs": 16378.326562499979, + "cpuNs": 16232.5 + }, + { + "wallNs": 21531.31374999987, + "cpuNs": 21537.5 + }, + { + "wallNs": 16817.159062499628, + "cpuNs": 16863.125 + }, + { + "wallNs": 17512.75468750009, + "cpuNs": 17484.6875 + }, + { + "wallNs": 19468.716249999718, + "cpuNs": 19355.9375 + } + ], + "p10Ns": 16475.88312500034, + "p90Ns": 21531.31374999987, + "opsPerSecond": 59463.075557743134 + } + ] +} diff --git a/packages/rescript-relay/src/prepareConversion.js b/packages/rescript-relay/src/prepareConversion.js index cb2a89e9..6448952e 100644 --- a/packages/rescript-relay/src/prepareConversion.js +++ b/packages/rescript-relay/src/prepareConversion.js @@ -90,7 +90,6 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { return result === undefined ? values : result; } function arrayOf(convert) { - if (convert === nullableOnly) return nullableArray; return (values) => { let result; for (let i = 0; i < values.length; i++) { @@ -105,7 +104,7 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { return result === undefined ? values : result; }; } - const anyArray = arrayOf(any); + const anyArray = arrayOf((value) => any(value)); function any(value) { if (value == null) return nullable; if (typeof value !== "object" || isOption(value)) return value; @@ -218,7 +217,9 @@ function prepareConversion(plan, callbacks, nullable, rootName = "__root") { } } convert = optional(convert); - for (let i = 0; i < depth; i++) convert = optional(arrayOf(convert)); + for (let i = 0; i < depth; i++) { + convert = optional(convert === nullableOnly ? nullableArray : arrayOf(convert)); + } return convert; } for (const name of Object.keys(roots)) From 86d3049f7234430977eb6008ec9ac05ddac34cfd Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 13:02:05 +0200 Subject: [PATCH 14/23] Record final performance comparison against current default branch --- packages/rescript-relay/benchmarks/RESULTS.md | 33 ++++++ .../main-comparison-final-forward.json | 102 ++++++++++++++++++ .../main-comparison-final-reverse.json | 102 ++++++++++++++++++ .../main-comparison-main-forward.json | 93 ++++++++++++++++ .../main-comparison-main-reverse.json | 93 ++++++++++++++++ 5 files changed, 423 insertions(+) create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-final-forward.json create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-final-reverse.json create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-main-forward.json create mode 100644 packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-main-reverse.json diff --git a/packages/rescript-relay/benchmarks/RESULTS.md b/packages/rescript-relay/benchmarks/RESULTS.md index 359f46b8..746cd85a 100644 --- a/packages/rescript-relay/benchmarks/RESULTS.md +++ b/packages/rescript-relay/benchmarks/RESULTS.md @@ -75,3 +75,36 @@ ESM/CommonJS parity, and artifact size budgets pass. The six new tests exercise opaque-list nulls/holes/inherited elements/cyclic values and generic-object metadata, inherited keys, own-key order and identity preservation in both nullable directions. Coverage and mutations provide evidence, not exhaustive correctness. + +## Final result against the current default branch + +Verified that the remote default branch is still `520cac4933c118a85cf0dffcd1a19a5dba34ad4f`. +Fresh runs compare its legacy runtime directly with the final prepared runtime at +`e1b12c7`, using the same version 3 fixtures, Node 24.16.0, 9 samples per case and +25 ms calibration targets. Run order was baseline/final, then final/baseline; +CPU affinity was unrestricted. These are measured microbenchmark ranges, not +application-wide latency claims or products of earlier benchmark ratios. + +| Case | Final speedup over current default branch | +| --- | ---: | +| Small fragment | 13.4–14.3× | +| Unchanged object | 17.9–18.9× | +| Nullable query | 17.0–17.1× | +| Connection, 100 rows | 41.2–45.3× | +| Plural fragment, 100 rows | 11.5–11.7× | +| Union list, 100 rows | 12.9–14.4× | +| Opaque JSON list | 3.6–3.7× | +| Recursive inputs | 19.2–23.0× | +| Custom scalar list | 5–7% more time (slower) | + +Raw reports are `results/js-specialization/main-comparison-*.json`. +The current machine remains noisy; treat these as approximate workload-specific +results. The scalar fixture is dominated by Date construction. + +For the same 129 generated artifacts, combined gzip decreased from 37,573 to +36,319 bytes (-1,254). The complete CommonJS-entry runtime increased from 1,144 +to 2,409 gzip bytes (+1,265). Adding these separately compressed components gives +38,717 → 38,728 bytes: effectively size-neutral for this fixture set. This is not +a measurement of a single compressed application bundle; actual results depend +on artifact count, splitting, imports and compression. See `SIZE.md` for separate +artifact bundles and native ESM runtime measurements. diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-final-forward.json b/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-final-forward.json new file mode 100644 index 00000000..df90cf86 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-final-forward.json @@ -0,0 +1,102 @@ +{ + "fixtureVersion": 3, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 9, + "durationMs": 25, + "implementation": "src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 6166.008999999999, + "medianNs": 97.32978027343741, + "p10Ns": 93.57615478515616, + "p90Ns": 106.187236328125, + "opsPerSecond": 10274347.657937879 + }, + { + "name": "unchanged object", + "iterations": 819200, + "newOutputObjects": 0, + "preparationNs": 0, + "medianNs": 43.0706787109375, + "p10Ns": 42.05908691406246, + "p90Ns": 68.60466064453118, + "opsPerSecond": 23217651.310102455 + }, + { + "name": "nullable query", + "iterations": 409600, + "newOutputObjects": 3, + "preparationNs": 0, + "medianNs": 120.18717285156245, + "p10Ns": 114.3510473632814, + "p90Ns": 192.49034912109386, + "opsPerSecond": 8320355.461185971 + }, + { + "name": "connection / 100 rows", + "iterations": 1600, + "newOutputObjects": 403, + "preparationNs": 3310.2939999998853, + "medianNs": 16611.42062500005, + "p10Ns": 16069.923124999974, + "p90Ns": 29744.175624999938, + "opsPerSecond": 60199.5472015806 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 3200, + "newOutputObjects": 301, + "preparationNs": 1250.7120000000214, + "medianNs": 12767.827812500058, + "p10Ns": 12063.315937499938, + "p90Ns": 19323.372500000034, + "opsPerSecond": 78321.8582428698 + }, + { + "name": "union list / 100 rows", + "iterations": 3200, + "newOutputObjects": 302, + "preparationNs": 2579.252999999881, + "medianNs": 15920.618749999989, + "p10Ns": 15137.376874999973, + "p90Ns": 24660.72499999996, + "opsPerSecond": 62811.62910204107 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "preparationNs": 1769.7540000003755, + "medianNs": 12097.4425, + "p10Ns": 11560.428437500006, + "p90Ns": 16572.76968749997, + "opsPerSecond": 82662.09986118968 + }, + { + "name": "opaque JSON list", + "iterations": 204800, + "newOutputObjects": 0, + "preparationNs": 1671.7290000001412, + "medianNs": 157.8011572265625, + "p10Ns": 151.1920361328123, + "p90Ns": 209.99336425781223, + "opsPerSecond": 6337089.141648392 + }, + { + "name": "recursive inputs", + "iterations": 1600, + "newOutputObjects": 103, + "preparationNs": 3554.1239999997742, + "medianNs": 15456.345000000056, + "p10Ns": 14703.716250000129, + "p90Ns": 18651.30625000006, + "opsPerSecond": 64698.34880109084 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-final-reverse.json b/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-final-reverse.json new file mode 100644 index 00000000..0b745557 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-final-reverse.json @@ -0,0 +1,102 @@ +{ + "fixtureVersion": 3, + "mode": "prepared", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 9, + "durationMs": 25, + "implementation": "src/utils.js", + "results": [ + { + "name": "small fragment", + "iterations": 204800, + "newOutputObjects": 3, + "preparationNs": 3729.476000000002, + "medianNs": 96.39559570312498, + "p10Ns": 95.44668457031239, + "p90Ns": 195.75591796875, + "opsPerSecond": 10373917.944132604 + }, + { + "name": "unchanged object", + "iterations": 819200, + "newOutputObjects": 0, + "preparationNs": 0, + "medianNs": 42.319431152343796, + "p10Ns": 41.3546801757813, + "p90Ns": 74.16593627929694, + "opsPerSecond": 23629807.224963527 + }, + { + "name": "nullable query", + "iterations": 204800, + "newOutputObjects": 3, + "preparationNs": 0, + "medianNs": 116.07211914062498, + "p10Ns": 111.87082519531266, + "p90Ns": 131.54970703125045, + "opsPerSecond": 8615333.358293122 + }, + { + "name": "connection / 100 rows", + "iterations": 1600, + "newOutputObjects": 403, + "preparationNs": 4470.445999999924, + "medianNs": 17709.131875, + "p10Ns": 16565.07750000003, + "p90Ns": 30430.39124999993, + "opsPerSecond": 56468.04185877124 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 3200, + "newOutputObjects": 301, + "preparationNs": 1157.4470000000474, + "medianNs": 12995.436249999984, + "p10Ns": 12703.703749999988, + "p90Ns": 21948.250625000015, + "opsPerSecond": 76950.09084439171 + }, + { + "name": "union list / 100 rows", + "iterations": 1600, + "newOutputObjects": 302, + "preparationNs": 3264.897999999903, + "medianNs": 17192.819375, + "p10Ns": 16707.176875000016, + "p90Ns": 27857.229374999977, + "opsPerSecond": 58163.8170092158 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "preparationNs": 1576.9289999998364, + "medianNs": 11855.260312499922, + "p10Ns": 11338.465312500004, + "p90Ns": 12947.777499999944, + "opsPerSecond": 84350.74166575847 + }, + { + "name": "opaque JSON list", + "iterations": 204800, + "newOutputObjects": 0, + "preparationNs": 1933.8830000001508, + "medianNs": 152.8652148437515, + "p10Ns": 139.65491210937486, + "p90Ns": 172.61145996093853, + "opsPerSecond": 6541710.624108517 + }, + { + "name": "recursive inputs", + "iterations": 3200, + "newOutputObjects": 103, + "preparationNs": 3667.729000000236, + "medianNs": 16676.562500000073, + "p10Ns": 15707.992187499967, + "p90Ns": 24262.58218749993, + "opsPerSecond": 59964.39613979174 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-main-forward.json b/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-main-forward.json new file mode 100644 index 00000000..bdcd6606 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-main-forward.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 3, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 9, + "durationMs": 25, + "implementation": "/tmp/relay-final-main-comparison/main.cjs", + "results": [ + { + "name": "small fragment", + "iterations": 25600, + "newOutputObjects": 3, + "medianNs": 1304.318124999999, + "p10Ns": 1260.6379296875002, + "p90Ns": 1445.466796875, + "opsPerSecond": 766684.1247030902 + }, + { + "name": "unchanged object", + "iterations": 51200, + "newOutputObjects": 1, + "medianNs": 772.4417578125009, + "p10Ns": 754.6286132812497, + "p90Ns": 1082.844199218751, + "opsPerSecond": 1294595.9871873416 + }, + { + "name": "nullable query", + "iterations": 12800, + "newOutputObjects": 3, + "medianNs": 2048.8332812500066, + "p10Ns": 1998.1547656249977, + "p90Ns": 3130.81101562501, + "opsPerSecond": 488082.66106937383 + }, + { + "name": "connection / 100 rows", + "iterations": 100, + "newOutputObjects": 703, + "medianNs": 751973.3699999984, + "p10Ns": 717691.5099999997, + "p90Ns": 896565.6400000012, + "opsPerSecond": 1329.834326446962 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 200, + "newOutputObjects": 301, + "medianNs": 149238.90000000029, + "p10Ns": 135191.16500000108, + "p90Ns": 230516.00500000175, + "opsPerSecond": 6700.665845165021 + }, + { + "name": "union list / 100 rows", + "iterations": 100, + "newOutputObjects": 302, + "medianNs": 229196.509999997, + "p10Ns": 225978.93000000113, + "p90Ns": 238393.49000000313, + "opsPerSecond": 4363.068181099324 + }, + { + "name": "custom scalar list", + "iterations": 1600, + "newOutputObjects": 102, + "medianNs": 11483.595624999907, + "p10Ns": 11311.169999999891, + "p90Ns": 19132.070624999924, + "opsPerSecond": 87080.73957454489 + }, + { + "name": "opaque JSON list", + "iterations": 51200, + "newOutputObjects": 2, + "medianNs": 581.3015429687507, + "p10Ns": 571.5029687500017, + "p90Ns": 931.3527343750039, + "opsPerSecond": 1720277.5600644802 + }, + { + "name": "recursive inputs", + "iterations": 100, + "newOutputObjects": 203, + "medianNs": 355228.6199999981, + "p10Ns": 330462.7299999993, + "p90Ns": 382119.9200000001, + "opsPerSecond": 2815.088491462218 + } + ] +} diff --git a/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-main-reverse.json b/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-main-reverse.json new file mode 100644 index 00000000..923f66b2 --- /dev/null +++ b/packages/rescript-relay/benchmarks/results/js-specialization/main-comparison-main-reverse.json @@ -0,0 +1,93 @@ +{ + "fixtureVersion": 3, + "mode": "legacy", + "node": "v24.16.0", + "platform": "linux x64", + "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", + "samples": 9, + "durationMs": 25, + "implementation": "/tmp/relay-final-main-comparison/main.cjs", + "results": [ + { + "name": "small fragment", + "iterations": 12800, + "newOutputObjects": 3, + "medianNs": 1378.5340625000008, + "p10Ns": 1325.6826562500003, + "p90Ns": 1747.93515625, + "opsPerSecond": 725408.2631708634 + }, + { + "name": "unchanged object", + "iterations": 51200, + "newOutputObjects": 1, + "medianNs": 799.3844726562504, + "p10Ns": 753.2267773437505, + "p90Ns": 1190.4633593750002, + "opsPerSecond": 1250962.502032508 + }, + { + "name": "nullable query", + "iterations": 12800, + "newOutputObjects": 3, + "medianNs": 1988.8723437500032, + "p10Ns": 1969.679062499994, + "p90Ns": 2078.2349218749996, + "opsPerSecond": 502797.4787534668 + }, + { + "name": "connection / 100 rows", + "iterations": 100, + "newOutputObjects": 703, + "medianNs": 729746.7899999992, + "p10Ns": 719330.2099999982, + "p90Ns": 893077.760000001, + "opsPerSecond": 1370.3383333827355 + }, + { + "name": "plural fragment / 100 rows", + "iterations": 200, + "newOutputObjects": 301, + "medianNs": 149771.75999999986, + "p10Ns": 130623.02999999929, + "p90Ns": 211133.4850000003, + "opsPerSecond": 6676.826125298928 + }, + { + "name": "union list / 100 rows", + "iterations": 200, + "newOutputObjects": 302, + "medianNs": 221552.9249999986, + "p10Ns": 218264.11500000174, + "p90Ns": 326365.54499999876, + "opsPerSecond": 4513.594212308442 + }, + { + "name": "custom scalar list", + "iterations": 3200, + "newOutputObjects": 102, + "medianNs": 11099.958437499992, + "p10Ns": 10862.159062499897, + "p90Ns": 11798.778437500061, + "opsPerSecond": 90090.42742192706 + }, + { + "name": "opaque JSON list", + "iterations": 51200, + "newOutputObjects": 2, + "medianNs": 545.0711914062545, + "p10Ns": 537.633710937504, + "p90Ns": 711.2100781249975, + "opsPerSecond": 1834622.7350964076 + }, + { + "name": "recursive inputs", + "iterations": 100, + "newOutputObjects": 203, + "medianNs": 320075.90999999596, + "p10Ns": 299301.76000000304, + "p90Ns": 493538.5300000007, + "opsPerSecond": 3124.2588672168818 + } + ] +} From 64c0934353648417806e24578b65f354bb6a16db Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 13:35:22 +0200 Subject: [PATCH 15/23] Cover plural custom scalar and catch conversions through mounted Relay hooks --- packages/relay | 2 +- .../__tests__/Test_conversionPlural-tests.js | 58 ++++ .../__tests__/Test_conversionPlural.res | 37 +++ ...TestConversionPluralCatch_user_graphql.res | 88 ++++++ .../TestConversionPluralQuery_graphql.res | 255 ++++++++++++++++++ .../TestConversionPlural_user_graphql.res | 75 ++++++ .../docs/conversion-contract.md | 11 +- 7 files changed, 523 insertions(+), 3 deletions(-) create mode 100644 packages/rescript-relay/__tests__/Test_conversionPlural-tests.js create mode 100644 packages/rescript-relay/__tests__/Test_conversionPlural.res create mode 100644 packages/rescript-relay/__tests__/__generated__/TestConversionPluralCatch_user_graphql.res create mode 100644 packages/rescript-relay/__tests__/__generated__/TestConversionPluralQuery_graphql.res create mode 100644 packages/rescript-relay/__tests__/__generated__/TestConversionPlural_user_graphql.res diff --git a/packages/relay b/packages/relay index bd305ebb..62470698 160000 --- a/packages/relay +++ b/packages/relay @@ -1 +1 @@ -Subproject commit bd305ebbc23b054dd8d59dbf27218a6dbd174c3a +Subproject commit 6247069896de304fb409787050bb76974dead9d9 diff --git a/packages/rescript-relay/__tests__/Test_conversionPlural-tests.js b/packages/rescript-relay/__tests__/Test_conversionPlural-tests.js new file mode 100644 index 00000000..c95d319a --- /dev/null +++ b/packages/rescript-relay/__tests__/Test_conversionPlural-tests.js @@ -0,0 +1,58 @@ +const React = require("react"); +const { render, act } = require("@testing-library/react"); +const { RelayEnvironmentProvider } = require("react-relay"); +const { createMockEnvironment } = require("relay-test-utils"); +const { createOperationDescriptor } = require("relay-runtime"); +const { Query, Fragment, CatchFragment, caughtDates } = require("./Test_conversionPlural.bs"); +const { node } = require("./__generated__/TestConversionPluralQuery_graphql.bs"); + +test("plural fragments convert custom scalars, including inside catch results, across store updates", () => { + const environment = createMockEnvironment(); + const operation = createOperationDescriptor(node, {}); + const dates = ["2020-01-01T00:00:00.000Z", "2021-01-01T00:00:00.000Z"]; + const payload = values => ({ + users: { + edges: values.map((createdAt, index) => ({ + node: { id: String(index), createdAt, firstName: `User ${index}` }, + })), + }, + }); + environment.commitPayload(operation, payload(dates)); + let plain, caught; + function Probe() { + const query = Query.use(undefined, "store-only"); + const refs = query.users.edges.map(edge => edge.node.fragmentRefs); + plain = Fragment.use(refs); + caught = CatchFragment.use(refs); + return null; + } + render(React.createElement(RelayEnvironmentProvider, {environment}, React.createElement(Probe))); + const check = values => { + expect(plain.map(value => value.createdAt)).toEqual(values.map(value => new Date(value))); + expect(caught.map(value => value.ok)).toEqual(values.map(() => true)); + expect(caughtDates(caught)).toEqual(values); + expect(values.map((_, index) => + environment.getStore().getSource().get(String(index)).createdAt, + )).toEqual(values); + }; + check(dates); + const firstPlain = plain; + const firstCaught = caught; + const updated = dates.slice().reverse(); + act(() => environment.commitPayload(operation, payload(updated))); + check(updated); + expect(plain).not.toBe(firstPlain); + expect(caught).not.toBe(firstCaught); + expect(firstPlain.map(value => value.createdAt)).toEqual(dates.map(value => new Date(value))); + expect(caughtDates(firstCaught)).toEqual(dates); + + const mixed = payload(dates); + mixed.users.edges[0].node.firstName = null; + act(() => environment.commitPayload(operation, mixed)); + expect(caught.map(value => value.ok)).toEqual([false, true]); + expect(caught[0].errors).toHaveLength(1); + expect(caughtDates(caught)).toEqual([undefined, dates[1]]); + expect(plain.map(value => value.createdAt)).toEqual(dates.map(value => new Date(value))); + expect(environment.getStore().getSource().get("0").firstName).toBeNull(); + expect(environment.getStore().getSource().get("1").createdAt).toBe(dates[1]); +}); diff --git a/packages/rescript-relay/__tests__/Test_conversionPlural.res b/packages/rescript-relay/__tests__/Test_conversionPlural.res new file mode 100644 index 00000000..9f638708 --- /dev/null +++ b/packages/rescript-relay/__tests__/Test_conversionPlural.res @@ -0,0 +1,37 @@ +module Query = %relay(` + query TestConversionPluralQuery { + users { + edges { + node { + id + ...TestConversionPlural_user + ...TestConversionPluralCatch_user + } + } + } + } +`) + +module Fragment = %relay(` + fragment TestConversionPlural_user on User @relay(plural: true) { + id + createdAt + } +`) + +module CatchFragment = %relay(` + fragment TestConversionPluralCatch_user on User @relay(plural: true) @catch { + firstName @required(action: THROW) + id + createdAt + } +`) + +// Compile-time check of the plural result wrapper and its converted scalar type. +let caughtDates = (values: TestConversionPluralCatch_user_graphql.Types.fragment) => + values->Array.map(value => + switch value { + | Ok({value}) => Some(value.createdAt->Date.toISOString) + | Error(_) => None + } + ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPluralCatch_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralCatch_user_graphql.res new file mode 100644 index 00000000..12e0faf9 --- /dev/null +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralCatch_user_graphql.res @@ -0,0 +1,88 @@ +/* @sourceLoc Test_conversionPlural.res */ +/* @generated */ +%%raw("/* @generated */") +module Types = { + @@warning("-30") + + type fragment_t = { + createdAt: TestsUtils.Datetime.t, + firstName: string, + @live id: string, + } + type fragment = array> +} + +module Internal = { + @live + type fragmentRaw + %%private( + @live + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value","createdAt"],"scalar":"0"}]},"version":2}`) + @live + let fragmentCallbacks = { + "0": TestsUtils.Datetime.parse, + } + @live + let preparedFragmentConverter = RescriptRelay.prepareConversion( + fragmentConverter, + fragmentCallbacks, + None + ) + ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) +} + +type t +type fragmentRef +external getFragmentRef: + array | #TestConversionPluralCatch_user]>> => fragmentRef = "%identity" + +module Utils = { + @@warning("-33") + open Types +} + +type relayOperationNode +type operationType = RescriptRelay.fragmentNode + + +let node: operationType = %raw(json` { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true, + "catchTo": "RESULT" + }, + "name": "TestConversionPluralCatch_user", + "selections": [ + { + "kind": "RequiredField", + "field": { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "firstName", + "storageKey": null + }, + "action": "THROW" + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +} `) + diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPluralQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralQuery_graphql.res new file mode 100644 index 00000000..060e8cb0 --- /dev/null +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralQuery_graphql.res @@ -0,0 +1,255 @@ +/* @sourceLoc Test_conversionPlural.res */ +/* @generated */ +%%raw("/* @generated */") +module Types = { + @@warning("-30") + + type rec response_users_edges_node = { + @live id: string, + fragmentRefs: RescriptRelay.fragmentRefs<[ | #TestConversionPluralCatch_user | #TestConversionPlural_user]>, + } + and response_users_edges = { + node: option, + } + and response_users = { + edges: option>>, + } + type response = { + users: option, + } + @live + type rawResponse = response + @live + type variables = unit + @live + type refetchVariables = unit + @live let makeRefetchVariables = () => () +} + + +type queryRef + +module Internal = { + @live + let convertVariables = value => RescriptRelay.convertWithoutPlan(value, None) + @live + type wrapResponseRaw + %%private( + @live + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}`) + @live + let wrapResponseCallbacks = () + @live + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( + wrapResponseConverter, + wrapResponseCallbacks, + null + ) + ) + @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live + type responseRaw + %%private( + @live + let responseConverter = wrapResponseConverter + @live + let responseCallbacks = () + @live + let preparedResponseConverter = RescriptRelay.prepareConversion( + responseConverter, + responseCallbacks, + None + ) + ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + type wrapRawResponseRaw = wrapResponseRaw + @live + let convertWrapRawResponse = convertWrapResponse + type rawResponseRaw = responseRaw + @live + let convertRawResponse = convertResponse + type rawPreloadToken<'response> = {source: Nullable.t>} + external tokenToRaw: queryRef => rawPreloadToken = "%identity" +} +module Utils = { + @@warning("-33") + open Types +} + +type relayOperationNode +type operationType = RescriptRelay.queryNode + + +let node: operationType = %raw(json` (function(){ +var v0 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null +}; +return { + "fragment": { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "TestConversionPluralQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "UserConnection", + "kind": "LinkedField", + "name": "users", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "UserEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "TestConversionPlural_user" + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "TestConversionPluralCatch_user" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": [], + "kind": "Operation", + "name": "TestConversionPluralQuery", + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "UserConnection", + "kind": "LinkedField", + "name": "users", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "UserEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "User", + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v0/*: any*/), + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "firstName", + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ] + }, + "params": { + "cacheID": "529ae8acb8b39777f39e2996f143b276", + "id": null, + "metadata": {}, + "name": "TestConversionPluralQuery", + "operationKind": "query", + "text": "query TestConversionPluralQuery {\n users {\n edges {\n node {\n id\n ...TestConversionPlural_user\n ...TestConversionPluralCatch_user\n }\n }\n }\n}\n\nfragment TestConversionPluralCatch_user on User {\n firstName\n id\n createdAt\n}\n\nfragment TestConversionPlural_user on User {\n id\n createdAt\n}\n" + } +}; +})() `) + +@live let load: ( + ~environment: RescriptRelay.Environment.t, + ~variables: Types.variables, + ~fetchPolicy: RescriptRelay.fetchPolicy=?, + ~fetchKey: string=?, + ~networkCacheConfig: RescriptRelay.cacheConfig=?, +) => queryRef = ( + ~environment, + ~variables, + ~fetchPolicy=?, + ~fetchKey=?, + ~networkCacheConfig=?, +) => + RescriptRelayReact.loadQuery( + environment, + node, + variables->Internal.convertVariables, + { + fetchKey, + fetchPolicy, + networkCacheConfig, + }, + ) + +@live +let queryRefToObservable = token => { + let raw = token->Internal.tokenToRaw + raw.source->Nullable.toOption +} + +@live +let queryRefToPromise = token => { + Promise.make((resolve, _reject) => { + switch token->queryRefToObservable { + | None => resolve(Error()) + | Some(o) => + open RescriptRelay.Observable + let _: subscription = o->subscribe(makeObserver(~complete=() => resolve(Ok()))) + } + }) +} diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPlural_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPlural_user_graphql.res new file mode 100644 index 00000000..86c108ba --- /dev/null +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPlural_user_graphql.res @@ -0,0 +1,75 @@ +/* @sourceLoc Test_conversionPlural.res */ +/* @generated */ +%%raw("/* @generated */") +module Types = { + @@warning("-30") + + type fragment_t = { + createdAt: TestsUtils.Datetime.t, + @live id: string, + } + type fragment = array +} + +module Internal = { + @live + type fragmentRaw + %%private( + @live + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["createdAt"],"scalar":"0"}]},"version":2}`) + @live + let fragmentCallbacks = { + "0": TestsUtils.Datetime.parse, + } + @live + let preparedFragmentConverter = RescriptRelay.prepareConversion( + fragmentConverter, + fragmentCallbacks, + None + ) + ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) +} + +type t +type fragmentRef +external getFragmentRef: + array | #TestConversionPlural_user]>> => fragmentRef = "%identity" + +module Utils = { + @@warning("-33") + open Types +} + +type relayOperationNode +type operationType = RescriptRelay.fragmentNode + + +let node: operationType = %raw(json` { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true + }, + "name": "TestConversionPlural_user", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +} `) + diff --git a/packages/rescript-relay/docs/conversion-contract.md b/packages/rescript-relay/docs/conversion-contract.md index aef96f78..b787cdbb 100644 --- a/packages/rescript-relay/docs/conversion-contract.md +++ b/packages/rescript-relay/docs/conversion-contract.md @@ -102,7 +102,7 @@ and documented remaining limitations—not a claim of absolute certainty. ## Compiler and package verification The compiler changes are in [draft zth/relay#40](https://github.com/zth/relay/pull/40), -pinned by this branch's submodule revision. All 30 compiler library tests pass. +pinned by this branch's submodule revision. All 34 compiler library tests pass. The broader upstream Flow snapshot suite has 64 failures and 93 passes on both the unchanged pinned compiler and this branch, with identical failing test names. These existing failures remain outside this conversion change. @@ -110,7 +110,7 @@ These existing failures remain outside this conversion change. The runtime is tested through both CommonJS and native ESM release modules. Run `yarn test:all` and `yarn test:conversion:mutations` from the package. The mutation check runs isolated copies and requires behavioral test failures for -13 deliberately introduced faults; it does not claim a comprehensive mutation score. +18 deliberately introduced faults; it does not claim a comprehensive mutation score. ## Generated size and sharing @@ -132,3 +132,10 @@ exists at or below that path. Generic nullable traversal handles those plain lists. List wrappers around scalars, unions, references, opaque values, and fragment-bearing records are retained. An entirely empty plan uses the shared converter; named input references are never removed by this optimization. + +Plural fragment roots apply their record plan to each element without a redundant +root list instruction. For plural fragments with `@catch`, each element is a +`CatchResult`, so the generated type is `array>` and +custom scalar paths start inside each result's `value`. Mounted hook tests cover +successful results, mixed success/error results, store updates, and preservation +of the raw Relay store; a typed ReScript helper checks the generated wrapper. From 65d953fb91a04ea8d69815522c0a2bb71e6c6ce7 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 13:47:12 +0200 Subject: [PATCH 16/23] Exercise caught plural nullable, union and interface payloads --- packages/relay | 2 +- .../__tests__/Test_conversionPlural-tests.js | 28 ++- .../__tests__/Test_conversionPlural.res | 66 ++++++ .../TestConversionPluralNode_node_graphql.res | 111 ++++++++++ ...tConversionPluralNullable_user_graphql.res | 80 ++++++++ .../TestConversionPluralQuery_graphql.res | 191 ++++++++++++++++-- ...stConversionPluralUnion_member_graphql.res | 123 +++++++++++ .../docs/conversion-contract.md | 5 +- 8 files changed, 582 insertions(+), 24 deletions(-) create mode 100644 packages/rescript-relay/__tests__/__generated__/TestConversionPluralNode_node_graphql.res create mode 100644 packages/rescript-relay/__tests__/__generated__/TestConversionPluralNullable_user_graphql.res create mode 100644 packages/rescript-relay/__tests__/__generated__/TestConversionPluralUnion_member_graphql.res diff --git a/packages/relay b/packages/relay index 62470698..19bfb3d8 160000 --- a/packages/relay +++ b/packages/relay @@ -1 +1 @@ -Subproject commit 6247069896de304fb409787050bb76974dead9d9 +Subproject commit 19bfb3d85aebe62ab279c02ba002b8f83343004f diff --git a/packages/rescript-relay/__tests__/Test_conversionPlural-tests.js b/packages/rescript-relay/__tests__/Test_conversionPlural-tests.js index c95d319a..127309b5 100644 --- a/packages/rescript-relay/__tests__/Test_conversionPlural-tests.js +++ b/packages/rescript-relay/__tests__/Test_conversionPlural-tests.js @@ -3,27 +3,37 @@ const { render, act } = require("@testing-library/react"); const { RelayEnvironmentProvider } = require("react-relay"); const { createMockEnvironment } = require("relay-test-utils"); const { createOperationDescriptor } = require("relay-runtime"); -const { Query, Fragment, CatchFragment, caughtDates } = require("./Test_conversionPlural.bs"); +const { Query, Fragment, CatchFragment, NullableFragment, UnionFragment, NodeFragment, caughtDates, nullableDates, unionValues, nodeValues } = require("./Test_conversionPlural.bs"); const { node } = require("./__generated__/TestConversionPluralQuery_graphql.bs"); -test("plural fragments convert custom scalars, including inside catch results, across store updates", () => { +test("plural caught fragments convert concrete, nullable, union and interface payloads across store updates", () => { const environment = createMockEnvironment(); const operation = createOperationDescriptor(node, {}); const dates = ["2020-01-01T00:00:00.000Z", "2021-01-01T00:00:00.000Z"]; const payload = values => ({ + members: { + edges: [ + { node: { __typename: "User", id: "0", createdAt: values[0], firstName: "User 0" } }, + { node: { __typename: "Group", id: "group", name: "Group name" } }, + ], + }, users: { edges: values.map((createdAt, index) => ({ - node: { id: String(index), createdAt, firstName: `User ${index}` }, + node: { __typename: "User", id: String(index), createdAt, firstName: `User ${index}` }, })), }, }); environment.commitPayload(operation, payload(dates)); - let plain, caught; + let plain, caught, nullable, union, nodes; function Probe() { const query = Query.use(undefined, "store-only"); const refs = query.users.edges.map(edge => edge.node.fragmentRefs); plain = Fragment.use(refs); caught = CatchFragment.use(refs); + nullable = NullableFragment.use(refs); + const memberRefs = query.members.edges.map(edge => edge.node.fragmentRefs); + union = UnionFragment.use(memberRefs); + nodes = NodeFragment.use(memberRefs); return null; } render(React.createElement(RelayEnvironmentProvider, {environment}, React.createElement(Probe))); @@ -31,6 +41,9 @@ test("plural fragments convert custom scalars, including inside catch results, a expect(plain.map(value => value.createdAt)).toEqual(values.map(value => new Date(value))); expect(caught.map(value => value.ok)).toEqual(values.map(() => true)); expect(caughtDates(caught)).toEqual(values); + expect(nullableDates(nullable)).toEqual(values); + expect(unionValues(union)).toEqual([values[0], "Group name"]); + expect(nodeValues(nodes)).toEqual([values[0], "Group name"]); expect(values.map((_, index) => environment.getStore().getSource().get(String(index)).createdAt, )).toEqual(values); @@ -48,10 +61,17 @@ test("plural fragments convert custom scalars, including inside catch results, a const mixed = payload(dates); mixed.users.edges[0].node.firstName = null; + mixed.members.edges[0].node.firstName = null; act(() => environment.commitPayload(operation, mixed)); expect(caught.map(value => value.ok)).toEqual([false, true]); expect(caught[0].errors).toHaveLength(1); expect(caughtDates(caught)).toEqual([undefined, dates[1]]); + expect(nullable.map(value => value.ok)).toEqual([true, true]); + expect(nullable[0].value).toBeUndefined(); + expect(nullableDates(nullable)).toEqual([undefined, dates[1]]); + expect(union.map(value => value.ok)).toEqual([false, true]); + expect(unionValues(union)).toEqual([undefined, "Group name"]); + expect(nodeValues(nodes)).toEqual([dates[0], "Group name"]); expect(plain.map(value => value.createdAt)).toEqual(dates.map(value => new Date(value))); expect(environment.getStore().getSource().get("0").firstName).toBeNull(); expect(environment.getStore().getSource().get("1").createdAt).toBe(dates[1]); diff --git a/packages/rescript-relay/__tests__/Test_conversionPlural.res b/packages/rescript-relay/__tests__/Test_conversionPlural.res index 9f638708..fe16bfc2 100644 --- a/packages/rescript-relay/__tests__/Test_conversionPlural.res +++ b/packages/rescript-relay/__tests__/Test_conversionPlural.res @@ -6,6 +6,16 @@ module Query = %relay(` id ...TestConversionPlural_user ...TestConversionPluralCatch_user + ...TestConversionPluralNullable_user + ...TestConversionPluralNode_node + } + } + } + members(groupId: "group") { + edges { + node { + ...TestConversionPluralUnion_member + ...TestConversionPluralNode_node } } } @@ -35,3 +45,59 @@ let caughtDates = (values: TestConversionPluralCatch_user_graphql.Types.fragment | Error(_) => None } ) + +module NullableFragment = %relay(` + fragment TestConversionPluralNullable_user on User @relay(plural: true) @catch { + firstName @required(action: NONE) + createdAt + } +`) + +module UnionFragment = %relay(` + fragment TestConversionPluralUnion_member on Member @relay(plural: true) @catch { + ... on User { + firstName @required(action: THROW) + createdAt + } + ... on Group { + name + } + } +`) + +module NodeFragment = %relay(` + fragment TestConversionPluralNode_node on Node @relay(plural: true) @catch { + ... on User { + createdAt + } + ... on Group { + name + } + } +`) + +let nullableDates = (values: TestConversionPluralNullable_user_graphql.Types.fragment) => + values->Array.map(value => + switch value { + | Ok({value: Some({createdAt})}) => Some(createdAt->Date.toISOString) + | _ => None + } + ) + +let unionValues = (values: TestConversionPluralUnion_member_graphql.Types.fragment) => + values->Array.map(value => + switch value { + | Ok({value: User({createdAt})}) => Some(createdAt->Date.toISOString) + | Ok({value: Group({name})}) => Some(name) + | _ => None + } + ) + +let nodeValues = (values: TestConversionPluralNode_node_graphql.Types.fragment) => + values->Array.map(value => + switch value { + | Ok({value: User({createdAt})}) => Some(createdAt->Date.toISOString) + | Ok({value: Group({name})}) => Some(name) + | _ => None + } + ) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPluralNode_node_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralNode_node_graphql.res new file mode 100644 index 00000000..5d2d206d --- /dev/null +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralNode_node_graphql.res @@ -0,0 +1,111 @@ +/* @sourceLoc Test_conversionPlural.res */ +/* @generated */ +%%raw("/* @generated */") +module Types = { + @@warning("-30") + + @tag("__typename") type fragment_t = + | @live Group( + { + name: string, + } + ) + | @live User( + { + createdAt: TestsUtils.Datetime.t, + } + ) + | @live @as("__unselected") UnselectedUnionMember(string) + + type fragment = array> +} + +@live +let unwrap_fragment_t: Types.fragment_t => Types.fragment_t = RescriptRelay_Internal.unwrapUnion(_, ["Group", "User"]) +@live +let wrap_fragment_t: Types.fragment_t => Types.fragment_t = RescriptRelay_Internal.wrapUnion +module Internal = { + @live + type fragmentRaw + %%private( + @live + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value"],"union":"1"},{"path":["value","User","createdAt"],"scalar":"0"}]},"version":2}`) + @live + let fragmentCallbacks = { + "0": TestsUtils.Datetime.parse, + "1": unwrap_fragment_t, + } + @live + let preparedFragmentConverter = RescriptRelay.prepareConversion( + fragmentConverter, + fragmentCallbacks, + None + ) + ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) +} + +type t +type fragmentRef +external getFragmentRef: + array | #TestConversionPluralNode_node]>> => fragmentRef = "%identity" + +module Utils = { + @@warning("-33") + open Types +} + +type relayOperationNode +type operationType = RescriptRelay.fragmentNode + + +let node: operationType = %raw(json` { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true, + "catchTo": "RESULT" + }, + "name": "TestConversionPluralNode_node", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "Group", + "abstractKey": null + } + ], + "type": "Node", + "abstractKey": "__isNode" +} `) + diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPluralNullable_user_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralNullable_user_graphql.res new file mode 100644 index 00000000..f74e3240 --- /dev/null +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralNullable_user_graphql.res @@ -0,0 +1,80 @@ +/* @sourceLoc Test_conversionPlural.res */ +/* @generated */ +%%raw("/* @generated */") +module Types = { + @@warning("-30") + + type fragment_t = { + createdAt: TestsUtils.Datetime.t, + firstName: string, + } + type fragment = array>> +} + +module Internal = { + @live + type fragmentRaw + %%private( + @live + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value","createdAt"],"scalar":"0"}]},"version":2}`) + @live + let fragmentCallbacks = { + "0": TestsUtils.Datetime.parse, + } + @live + let preparedFragmentConverter = RescriptRelay.prepareConversion( + fragmentConverter, + fragmentCallbacks, + None + ) + ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) +} + +type t +type fragmentRef +external getFragmentRef: + array | #TestConversionPluralNullable_user]>> => fragmentRef = "%identity" + +module Utils = { + @@warning("-33") + open Types +} + +type relayOperationNode +type operationType = RescriptRelay.fragmentNode + + +let node: operationType = %raw(json` { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true, + "catchTo": "RESULT" + }, + "name": "TestConversionPluralNullable_user", + "selections": [ + { + "kind": "RequiredField", + "field": { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "firstName", + "storageKey": null + }, + "action": "NONE" + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null +} `) + diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPluralQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralQuery_graphql.res index 060e8cb0..843d9c58 100644 --- a/packages/rescript-relay/__tests__/__generated__/TestConversionPluralQuery_graphql.res +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralQuery_graphql.res @@ -4,9 +4,19 @@ module Types = { @@warning("-30") - type rec response_users_edges_node = { + type rec response_members_edges_node = { + @live __typename: string, + fragmentRefs: RescriptRelay.fragmentRefs<[ | #TestConversionPluralNode_node | #TestConversionPluralUnion_member]>, + } + and response_members_edges = { + node: option, + } + and response_members = { + edges: option>>, + } + and response_users_edges_node = { @live id: string, - fragmentRefs: RescriptRelay.fragmentRefs<[ | #TestConversionPluralCatch_user | #TestConversionPlural_user]>, + fragmentRefs: RescriptRelay.fragmentRefs<[ | #TestConversionPluralCatch_user | #TestConversionPluralNode_node | #TestConversionPluralNullable_user | #TestConversionPlural_user]>, } and response_users_edges = { node: option, @@ -15,6 +25,7 @@ module Types = { edges: option>>, } type response = { + members: option, users: option, } @live @@ -36,7 +47,7 @@ module Internal = { type wrapResponseRaw %%private( @live - let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}`) + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"list":1,"path":["members","edges"]},{"fragments":true,"path":["members","edges","node"]},{"list":1,"path":["users","edges"]},{"fragments":true,"path":["users","edges","node"]}]},"version":2}`) @live let wrapResponseCallbacks = () @live @@ -89,6 +100,53 @@ var v0 = { "kind": "ScalarField", "name": "id", "storageKey": null +}, +v1 = { + "args": null, + "kind": "FragmentSpread", + "name": "TestConversionPluralNode_node" +}, +v2 = [ + { + "kind": "Literal", + "name": "groupId", + "value": "group" + } +], +v3 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null +}, +v4 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null +}, +v5 = { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "firstName", + "storageKey": null +}, +v6 = { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "Group", + "abstractKey": null }; return { "fragment": { @@ -131,7 +189,13 @@ return { "args": null, "kind": "FragmentSpread", "name": "TestConversionPluralCatch_user" - } + }, + { + "args": null, + "kind": "FragmentSpread", + "name": "TestConversionPluralNullable_user" + }, + (v1/*: any*/) ], "storageKey": null } @@ -140,6 +204,46 @@ return { } ], "storageKey": null + }, + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "MemberConnection", + "kind": "LinkedField", + "name": "members", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "MemberEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "args": null, + "kind": "FragmentSpread", + "name": "TestConversionPluralUnion_member" + }, + (v1/*: any*/) + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": "members(groupId:\"group\")" } ], "type": "Query", @@ -176,19 +280,72 @@ return { "plural": false, "selections": [ (v0/*: any*/), + (v4/*: any*/), + (v5/*: any*/), { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "createdAt", - "storageKey": null + "kind": "InlineFragment", + "selections": [ + (v3/*: any*/), + (v6/*: any*/) + ], + "type": "Node", + "abstractKey": "__isNode" + } + ], + "storageKey": null + } + ], + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": (v2/*: any*/), + "concreteType": "MemberConnection", + "kind": "LinkedField", + "name": "members", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "MemberEdge", + "kind": "LinkedField", + "name": "edges", + "plural": true, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": null, + "kind": "LinkedField", + "name": "node", + "plural": false, + "selections": [ + (v3/*: any*/), + { + "kind": "TypeDiscriminator", + "abstractKey": "__isMember" }, { - "alias": null, - "args": null, - "kind": "ScalarField", - "name": "firstName", - "storageKey": null + "kind": "InlineFragment", + "selections": [ + (v5/*: any*/), + (v4/*: any*/) + ], + "type": "User", + "abstractKey": null + }, + (v6/*: any*/), + { + "kind": "InlineFragment", + "selections": [ + (v0/*: any*/) + ], + "type": "Node", + "abstractKey": "__isNode" } ], "storageKey": null @@ -197,17 +354,17 @@ return { "storageKey": null } ], - "storageKey": null + "storageKey": "members(groupId:\"group\")" } ] }, "params": { - "cacheID": "529ae8acb8b39777f39e2996f143b276", + "cacheID": "12b21ea36baea2bc4e53962113b3c70f", "id": null, "metadata": {}, "name": "TestConversionPluralQuery", "operationKind": "query", - "text": "query TestConversionPluralQuery {\n users {\n edges {\n node {\n id\n ...TestConversionPlural_user\n ...TestConversionPluralCatch_user\n }\n }\n }\n}\n\nfragment TestConversionPluralCatch_user on User {\n firstName\n id\n createdAt\n}\n\nfragment TestConversionPlural_user on User {\n id\n createdAt\n}\n" + "text": "query TestConversionPluralQuery {\n users {\n edges {\n node {\n id\n ...TestConversionPlural_user\n ...TestConversionPluralCatch_user\n ...TestConversionPluralNullable_user\n ...TestConversionPluralNode_node\n }\n }\n }\n members(groupId: \"group\") {\n edges {\n node {\n __typename\n ...TestConversionPluralUnion_member\n ...TestConversionPluralNode_node\n ... on Node {\n __isNode: __typename\n __typename\n id\n }\n }\n }\n }\n}\n\nfragment TestConversionPluralCatch_user on User {\n firstName\n id\n createdAt\n}\n\nfragment TestConversionPluralNode_node on Node {\n __isNode: __typename\n __typename\n ... on User {\n createdAt\n }\n ... on Group {\n name\n }\n}\n\nfragment TestConversionPluralNullable_user on User {\n firstName\n createdAt\n}\n\nfragment TestConversionPluralUnion_member on Member {\n __isMember: __typename\n __typename\n ... on User {\n firstName\n createdAt\n }\n ... on Group {\n name\n }\n}\n\nfragment TestConversionPlural_user on User {\n id\n createdAt\n}\n" } }; })() `) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPluralUnion_member_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralUnion_member_graphql.res new file mode 100644 index 00000000..40c53b25 --- /dev/null +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPluralUnion_member_graphql.res @@ -0,0 +1,123 @@ +/* @sourceLoc Test_conversionPlural.res */ +/* @generated */ +%%raw("/* @generated */") +module Types = { + @@warning("-30") + + @tag("__typename") type fragment_t = + | @live Group( + { + name: string, + } + ) + | @live User( + { + createdAt: TestsUtils.Datetime.t, + firstName: string, + } + ) + | @live @as("__unselected") UnselectedUnionMember(string) + + type fragment = array> +} + +@live +let unwrap_fragment_t: Types.fragment_t => Types.fragment_t = RescriptRelay_Internal.unwrapUnion(_, ["Group", "User"]) +@live +let wrap_fragment_t: Types.fragment_t => Types.fragment_t = RescriptRelay_Internal.wrapUnion +module Internal = { + @live + type fragmentRaw + %%private( + @live + let fragmentConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["value"],"union":"1"},{"path":["value","User","createdAt"],"scalar":"0"}]},"version":2}`) + @live + let fragmentCallbacks = { + "0": TestsUtils.Datetime.parse, + "1": unwrap_fragment_t, + } + @live + let preparedFragmentConverter = RescriptRelay.prepareConversion( + fragmentConverter, + fragmentCallbacks, + None + ) + ) + @live + let convertFragment = value => RescriptRelay.runConversion(preparedFragmentConverter, value) +} + +type t +type fragmentRef +external getFragmentRef: + array | #TestConversionPluralUnion_member]>> => fragmentRef = "%identity" + +module Utils = { + @@warning("-33") + open Types +} + +type relayOperationNode +type operationType = RescriptRelay.fragmentNode + + +let node: operationType = %raw(json` { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": { + "plural": true, + "catchTo": "RESULT" + }, + "name": "TestConversionPluralUnion_member", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "__typename", + "storageKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "kind": "RequiredField", + "field": { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "firstName", + "storageKey": null + }, + "action": "THROW" + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "createdAt", + "storageKey": null + } + ], + "type": "User", + "abstractKey": null + }, + { + "kind": "InlineFragment", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } + ], + "type": "Group", + "abstractKey": null + } + ], + "type": "Member", + "abstractKey": "__isMember" +} `) + diff --git a/packages/rescript-relay/docs/conversion-contract.md b/packages/rescript-relay/docs/conversion-contract.md index b787cdbb..cc46e167 100644 --- a/packages/rescript-relay/docs/conversion-contract.md +++ b/packages/rescript-relay/docs/conversion-contract.md @@ -102,7 +102,7 @@ and documented remaining limitations—not a claim of absolute certainty. ## Compiler and package verification The compiler changes are in [draft zth/relay#40](https://github.com/zth/relay/pull/40), -pinned by this branch's submodule revision. All 34 compiler library tests pass. +pinned by this branch's submodule revision. All 35 compiler library tests pass. The broader upstream Flow snapshot suite has 64 failures and 93 passes on both the unchanged pinned compiler and this branch, with identical failing test names. These existing failures remain outside this conversion change. @@ -137,5 +137,6 @@ Plural fragment roots apply their record plan to each element without a redundan root list instruction. For plural fragments with `@catch`, each element is a `CatchResult`, so the generated type is `array>` and custom scalar paths start inside each result's `value`. Mounted hook tests cover -successful results, mixed success/error results, store updates, and preservation +nullable payloads, union/interface payloads, mixed success/error results, store +updates, and preservation of the raw Relay store; a typed ReScript helper checks the generated wrapper. From 9adbc38de1a4cab7b279228250358535e76174b1 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Tue, 22 Sep 2026 21:16:39 +0200 Subject: [PATCH 17/23] Update compiler pin with regenerated ReScript test artifacts --- packages/relay | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/relay b/packages/relay index 19bfb3d8..24c0ec95 160000 --- a/packages/relay +++ b/packages/relay @@ -1 +1 @@ -Subproject commit 19bfb3d85aebe62ab279c02ba002b8f83343004f +Subproject commit 24c0ec9503478184bdd54b69dcd661650bbcb196 From e30347b149df9b617d62d81dcee06cb9ffe06dbb Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Wed, 23 Sep 2026 08:48:44 +0200 Subject: [PATCH 18/23] Build Linux PPX on supported Debian Bookworm --- .github/workflows/build-release.yml | 4 ++-- .github/workflows/ppx.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 0c88aac6..bd8113d1 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -20,7 +20,7 @@ jobs: name: Build PPX for release runs-on: ${{ matrix.platform }} container: - image: debian:bullseye + image: debian:bookworm defaults: run: working-directory: packages/rescript-relay/rescript-relay-ppx @@ -47,7 +47,7 @@ jobs: with: ocaml-compiler: "4.14" dune-cache: true - cache-prefix: "v2-bullseye" + cache-prefix: "v3-bookworm" - name: Install PPX dependencies run: opam install . --deps-only - name: Build PPX diff --git a/.github/workflows/ppx.yml b/.github/workflows/ppx.yml index 0155db8c..e8e16bdb 100644 --- a/.github/workflows/ppx.yml +++ b/.github/workflows/ppx.yml @@ -11,7 +11,7 @@ jobs: name: PPX Linux runs-on: ubuntu-latest container: - image: debian:bullseye + image: debian:bookworm steps: - name: Install system dependencies run: | @@ -29,7 +29,7 @@ jobs: with: ocaml-compiler: "4.14" dune-cache: true - cache-prefix: "v2-bullseye" + cache-prefix: "v3-bookworm" - name: Install dependencies working-directory: packages/rescript-relay/rescript-relay-ppx run: opam install . --deps-only From 721d788a793be1e15d526e72492e123ba41bdeca Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Wed, 23 Sep 2026 08:58:22 +0200 Subject: [PATCH 19/23] Install GPG for OCaml setup in Linux PPX containers --- .github/workflows/build-release.yml | 1 + .github/workflows/ppx.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index bd8113d1..6ae6a5cc 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -34,6 +34,7 @@ jobs: curl \ ca-certificates \ git \ + gpg \ unzip \ bubblewrap - uses: actions/checkout@v4 diff --git a/.github/workflows/ppx.yml b/.github/workflows/ppx.yml index e8e16bdb..abbc75f1 100644 --- a/.github/workflows/ppx.yml +++ b/.github/workflows/ppx.yml @@ -21,6 +21,7 @@ jobs: curl \ ca-certificates \ git \ + gpg \ unzip \ bubblewrap - uses: actions/checkout@v4 From f1d667cbe8b374b7191a1c5709a5537dcd87b19a Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Wed, 23 Sep 2026 09:05:17 +0200 Subject: [PATCH 20/23] Install complete GnuPG tools for OCaml signature verification --- .github/workflows/build-release.yml | 2 +- .github/workflows/ppx.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 6ae6a5cc..080f1f78 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -34,7 +34,7 @@ jobs: curl \ ca-certificates \ git \ - gpg \ + gnupg \ unzip \ bubblewrap - uses: actions/checkout@v4 diff --git a/.github/workflows/ppx.yml b/.github/workflows/ppx.yml index abbc75f1..78f257ba 100644 --- a/.github/workflows/ppx.yml +++ b/.github/workflows/ppx.yml @@ -21,7 +21,7 @@ jobs: curl \ ca-certificates \ git \ - gpg \ + gnupg \ unzip \ bubblewrap - uses: actions/checkout@v4 From 3b05c7a4e53efaf5db16adefa7a2fcf65642f80f Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Wed, 23 Sep 2026 09:58:23 +0200 Subject: [PATCH 21/23] Audit custom scalar ordering with permutation and mounted regressions --- CHANGELOG.md | 2 + .../__tests__/Test_conversionPlan-tests.js | 9 +- .../__tests__/Test_conversionPlan.res | 12 + ...TestConversionPlanReverseQuery_graphql.res | 261 ++++++++++++++++++ .../__tests__/utils-scalar-ordering-tests.js | 157 +++++++++++ .../docs/conversion-contract.md | 21 +- .../scripts/test-conversion-mutations.js | 12 +- 7 files changed, 470 insertions(+), 4 deletions(-) create mode 100644 packages/rescript-relay/__tests__/__generated__/TestConversionPlanReverseQuery_graphql.res create mode 100644 packages/rescript-relay/__tests__/utils-scalar-ordering-tests.js diff --git a/CHANGELOG.md b/CHANGELOG.md index e651bccf..dba48e48 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # master +- Speed up response and variable conversion with prepared conversion plans and smaller generated instructions. Fix custom-scalar, nested-list, union, and plural `@catch` conversion edge cases; expand regression coverage and add performance/bundle-size benchmarks. Compiler and runtime updates must ship together. + - fix remove-unused-fields command. https://github.com/zth/rescript-relay/pull/636 # 4.5.1 diff --git a/packages/rescript-relay/__tests__/Test_conversionPlan-tests.js b/packages/rescript-relay/__tests__/Test_conversionPlan-tests.js index aef6ccfb..2ac55e74 100644 --- a/packages/rescript-relay/__tests__/Test_conversionPlan-tests.js +++ b/packages/rescript-relay/__tests__/Test_conversionPlan-tests.js @@ -4,10 +4,15 @@ const { render, screen, act } = require("@testing-library/react"); const { RelayEnvironmentProvider } = require("react-relay"); const { createMockEnvironment } = require("relay-test-utils"); const { createOperationDescriptor } = require("relay-runtime"); -const { Query } = require("./Test_conversionPlan.bs"); +const { Query, ReverseQuery } = require("./Test_conversionPlan.bs"); const generated = require("./__generated__/TestConversionPlanQuery_graphql.bs"); -test("compiler plans preserve nulls, nested list depth and distinct paths through mounted hooks and writes", () => { +const reverseGenerated = require("./__generated__/TestConversionPlanReverseQuery_graphql.bs"); + +test.each([ + ["original", Query, generated], + ["reversed", ReverseQuery, reverseGenerated], +])("%s selection order preserves scalars, nulls and nested lists through mounted hooks and writes", (_, Query, generated) => { const environment = createMockEnvironment(); const variables = { input: { diff --git a/packages/rescript-relay/__tests__/Test_conversionPlan.res b/packages/rescript-relay/__tests__/Test_conversionPlan.res index 7e540ebd..8e8c5546 100644 --- a/packages/rescript-relay/__tests__/Test_conversionPlan.res +++ b/packages/rescript-relay/__tests__/Test_conversionPlan.res @@ -9,3 +9,15 @@ module Query = %relay(` } } `) + +module ReverseQuery = %relay(` + query TestConversionPlanReverseQuery($input: ConversionContractInput) { + conversionContract(input: $input) { + a { b } + a_b + raw + dates + grid + } + } +`) diff --git a/packages/rescript-relay/__tests__/__generated__/TestConversionPlanReverseQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestConversionPlanReverseQuery_graphql.res new file mode 100644 index 00000000..6f8804da --- /dev/null +++ b/packages/rescript-relay/__tests__/__generated__/TestConversionPlanReverseQuery_graphql.res @@ -0,0 +1,261 @@ +/* @sourceLoc Test_conversionPlan.res */ +/* @generated */ +%%raw("/* @generated */") +module Types = { + @@warning("-30") + + @live type conversionContractInput = RelaySchemaAssets_graphql.input_ConversionContractInput + type rec response_conversionContract_a = { + b: option, + } + and response_conversionContract = { + a: option, + a_b: option, + dates: option>>, + grid: option>>>>, + raw: option>>>>, + } + type response = { + conversionContract: response_conversionContract, + } + @live + type rawResponse = response + @live + type variables = { + input?: conversionContractInput, + } + @live + type refetchVariables = { + input?: option, + } + @live let makeRefetchVariables = ( + ~input=?, + ): refetchVariables => { + input: ?input + } + +} + + +type queryRef + +module Internal = { + %%private( + @live + let variablesConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["input"],"reference":"conversionContractInput"}],"conversionContractInput":[{"list":1,"path":["children"],"reference":"conversionContractInput"},{"list":2,"path":["grid"],"scalar":"0"}]},"version":2}`) + @live + let variablesCallbacks = { + "0": TestsUtils.ConversionNumber.serialize, + } + @live + let preparedVariablesConverter = RescriptRelay.prepareConversion( + variablesConverter, + variablesCallbacks, + None + ) + ) + @live + let convertVariables = value => RescriptRelay.runConversion(preparedVariablesConverter, value) + @live + type wrapResponseRaw + %%private( + @live + let wrapResponseConverter: JSON.t = %raw(json`{"roots":{"__root":[{"path":["conversionContract","a","b"],"scalar":"1"},{"path":["conversionContract","a_b"],"scalar":"0"},{"list":1,"path":["conversionContract","dates"],"scalar":"1"},{"list":2,"path":["conversionContract","grid"],"scalar":"0"},{"list":2,"opaque":true,"path":["conversionContract","raw"]}]},"version":2}`) + @live + let wrapResponseCallbacks = { + "0": TestsUtils.ConversionNumber.serialize, + "1": TestsUtils.Datetime.serialize, + } + @live + let preparedWrapResponseConverter = RescriptRelay.prepareConversion( + wrapResponseConverter, + wrapResponseCallbacks, + null + ) + ) + @live + let convertWrapResponse = value => RescriptRelay.runConversion(preparedWrapResponseConverter, value) + @live + type responseRaw + %%private( + @live + let responseConverter = wrapResponseConverter + @live + let responseCallbacks = { + "0": TestsUtils.ConversionNumber.parse, + "1": TestsUtils.Datetime.parse, + } + @live + let preparedResponseConverter = RescriptRelay.prepareConversion( + responseConverter, + responseCallbacks, + None + ) + ) + @live + let convertResponse = value => RescriptRelay.runConversion(preparedResponseConverter, value) + type wrapRawResponseRaw = wrapResponseRaw + @live + let convertWrapRawResponse = convertWrapResponse + type rawResponseRaw = responseRaw + @live + let convertRawResponse = convertResponse + type rawPreloadToken<'response> = {source: Nullable.t>} + external tokenToRaw: queryRef => rawPreloadToken = "%identity" +} +module Utils = { + @@warning("-33") + open Types +} + +type relayOperationNode +type operationType = RescriptRelay.queryNode + + +let node: operationType = %raw(json` (function(){ +var v0 = [ + { + "defaultValue": null, + "kind": "LocalArgument", + "name": "input" + } +], +v1 = [ + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": [ + { + "kind": "Variable", + "name": "input", + "variableName": "input" + } + ], + "concreteType": "ConversionContract", + "kind": "LinkedField", + "name": "conversionContract", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "concreteType": "ConversionContractNested", + "kind": "LinkedField", + "name": "a", + "plural": false, + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "b", + "storageKey": null + } + ], + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "a_b", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "raw", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "dates", + "storageKey": null + }, + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "grid", + "storageKey": null + } + ], + "storageKey": null + } + ] + } +]; +return { + "fragment": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Fragment", + "metadata": null, + "name": "TestConversionPlanReverseQuery", + "selections": (v1/*: any*/), + "type": "Query", + "abstractKey": null + }, + "kind": "Request", + "operation": { + "argumentDefinitions": (v0/*: any*/), + "kind": "Operation", + "name": "TestConversionPlanReverseQuery", + "selections": (v1/*: any*/) + }, + "params": { + "cacheID": "b2881739785e489cd64a009ebdb584d0", + "id": null, + "metadata": {}, + "name": "TestConversionPlanReverseQuery", + "operationKind": "query", + "text": null + } +}; +})() `) + +@live let load: ( + ~environment: RescriptRelay.Environment.t, + ~variables: Types.variables, + ~fetchPolicy: RescriptRelay.fetchPolicy=?, + ~fetchKey: string=?, + ~networkCacheConfig: RescriptRelay.cacheConfig=?, +) => queryRef = ( + ~environment, + ~variables, + ~fetchPolicy=?, + ~fetchKey=?, + ~networkCacheConfig=?, +) => + RescriptRelayReact.loadQuery( + environment, + node, + variables->Internal.convertVariables, + { + fetchKey, + fetchPolicy, + networkCacheConfig, + }, + ) + +@live +let queryRefToObservable = token => { + let raw = token->Internal.tokenToRaw + raw.source->Nullable.toOption +} + +@live +let queryRefToPromise = token => { + Promise.make((resolve, _reject) => { + switch token->queryRefToObservable { + | None => resolve(Error()) + | Some(o) => + open RescriptRelay.Observable + let _: subscription = o->subscribe(makeObserver(~complete=() => resolve(Ok()))) + } + }) +} diff --git a/packages/rescript-relay/__tests__/utils-scalar-ordering-tests.js b/packages/rescript-relay/__tests__/utils-scalar-ordering-tests.js new file mode 100644 index 00000000..6d21347d --- /dev/null +++ b/packages/rescript-relay/__tests__/utils-scalar-ordering-tests.js @@ -0,0 +1,157 @@ +const { traverser, prepareConversion } = require("../src/utils"); +const { freeze } = require("./helpers/conversionModel"); + +function permutations(values) { + if (values.length === 0) return [[]]; + return values.flatMap((value, index) => + permutations(values.filter((_, i) => i !== index)).map(rest => [value, ...rest]), + ); +} +const fields = ["single", "many", "nested", "nullable", "last"]; +const orders = permutations(fields); +const entries = [ + { path: ["single"], scalar: "single" }, + { path: ["many"], list: 1, scalar: "many" }, + { path: ["nested"], reference: "Input" }, + { path: ["last"], scalar: "last" }, +]; +const legacyEntries = [ + ["single", { c: "single" }], + ["many", { ca: "many" }], + ["nested", { r: "Input" }], + ["last", { c: "last" }], +]; + +describe.each(["legacy", "prepared"])("%s custom scalar ordering", runtime => { + test.each([undefined, null])("all 120 sibling orders and both instruction orders (nullable=%s)", nullable => { + for (const reversePlan of [false, true]) { + for (const order of orders) { + const source = { + single: [1], // One array-backed scalar, not a GraphQL list. + many: [[2], null, , [3]], // A sparse GraphQL list of array-backed scalars. + nested: { value: [4], after: null }, + nullable: null, + last: [5], + }; + const input = freeze(Object.fromEntries(order.map(key => [key, source[key]]))); + const trace = []; + const outputs = {}; + const callbacks = Object.fromEntries(["single", "many", "nested", "last"].map(name => [ + name, + value => { + trace.push([name, value]); + // Returning arrays/objects with nulls catches accidental traversal + // of parser/serializer results, including repeated conversion. + const result = freeze({ converted: value[0], untouched: [null] }); + outputs[value[0]] = result; + return result; + }, + ])); + const ordered = values => reversePlan ? values.slice().reverse() : values; + const convert = runtime === "prepared" + ? prepareConversion({ version: 2, roots: { + __root: ordered(entries), + Input: [{ path: ["value"], scalar: "nested" }], + } }, callbacks, nullable) + : value => traverser(value, { + __root: Object.fromEntries(ordered(legacyEntries)), + Input: { value: { c: "nested" } }, + }, callbacks, nullable); + const expectedTrace = order.flatMap(key => ({ + single: [["single", source.single]], + many: [["many", source.many[0]], ["many", source.many[3]]], + nested: [["nested", source.nested.value]], + nullable: [], + last: [["last", source.last]], + })[key]); + for (let call = 0; call < 2; call++) { + trace.length = 0; + const result = convert(input); + expect(trace).toStrictEqual(expectedTrace); + expect(result).toStrictEqual({ + single: outputs[1], + many: [outputs[2], nullable, , outputs[3]], + nested: { value: outputs[4], after: nullable }, + nullable, + last: outputs[5], + }); + expect(result.single).toBe(outputs[1]); + expect(result.many[0]).toBe(outputs[2]); + expect(Object.keys(result)).toEqual(order); + } + expect(input.single).toBe(source.single); + expect(input.nested.after).toBeNull(); + expect(input.nullable).toBeNull(); + } + } + }); + test.each([undefined, null])("empty scalar arrays differ from empty GraphQL lists (nullable=%s)", nullable => { + const single = []; + const element = []; + const callback = jest.fn(value => ({ raw: value })); + const input = freeze({ single, emptyList: [], list: [element, null], after: null }); + const convert = runtime === "prepared" + ? prepareConversion({ version: 2, roots: { __root: [ + { path: ["single"], scalar: "scalar" }, + { path: ["emptyList"], list: 1, scalar: "scalar" }, + { path: ["list"], list: 1, scalar: "scalar" }, + ] } }, { scalar: callback }, nullable) + : value => traverser(value, { __root: { + single: { c: "scalar" }, emptyList: { ca: "scalar" }, list: { ca: "scalar" }, + } }, { scalar: callback }, nullable); + const result = convert(input); + expect(callback).toHaveBeenCalledTimes(2); + expect(callback.mock.calls[0][0]).toBe(single); + expect(callback.mock.calls[1][0]).toBe(element); + expect(result.single.raw).toBe(single); + expect(result.emptyList).toEqual([]); + expect(result.list[0].raw).toBe(element); + expect(result.list[1]).toBe(nullable); + expect(result.after).toBe(nullable); + }); + +}); + +describe.each([undefined, null])("prepared scalar result boundary (nullable=%s)", nullable => { + test("all scalar results remain opaque at root, field and list positions", () => { + const results = [false, 0, "", null, undefined, [null], { value: null }, + { BS_PRIVATE_NESTED_SOME_NONE: 0 }, new Date("2020-01-01")]; + for (const returned of results) { + for (const position of ["root", "field", "list"]) { + const callback = jest.fn(() => returned); + const convert = prepareConversion({ version: 2, roots: { __root: [ + { path: position === "root" ? [] : ["value"], scalar: "scalar", + ...(position === "list" ? { list: 1 } : {}) }, + ] } }, { scalar: callback }, nullable); + const result = convert(freeze(position === "root" ? "wire" : { + value: position === "list" ? ["wire", null] : "wire", after: null, + })); + expect(position === "root" ? result : position === "list" ? result.value[0] : result.value).toBe(returned); + expect(callback).toHaveBeenCalledTimes(1); + expect(callback).toHaveBeenCalledWith("wire"); + if (position !== "root") expect(result.after).toBe(nullable); + if (position === "list") expect(result.value[1]).toBe(nullable); + } + } + }); + + test("list callback errors stop later elements and siblings, and do not poison subsequent calls", () => { + const failure = new Error("scalar failed"); + const trace = []; + const convert = prepareConversion({ version: 2, roots: { __root: [ + { path: ["values"], list: 1, scalar: "scalar" }, + { path: ["after"], scalar: "scalar" }, + ] } }, { scalar: value => { + trace.push(value); + if (value === "bad") throw failure; + return [value]; + } }, nullable); + const input = freeze({ values: ["first", "bad", "last"], after: "sibling" }); + expect(() => convert(input)).toThrow(failure); + expect(trace).toEqual(["first", "bad"]); + expect(input).toStrictEqual({ values: ["first", "bad", "last"], after: "sibling" }); + trace.length = 0; + expect(convert(freeze({ values: ["good"], after: "sibling" }))).toStrictEqual({ values: [["good"]], after: ["sibling"] }); + expect(trace).toEqual(["good", "sibling"]); + }); +}); diff --git a/packages/rescript-relay/docs/conversion-contract.md b/packages/rescript-relay/docs/conversion-contract.md index cc46e167..415d84f8 100644 --- a/packages/rescript-relay/docs/conversion-contract.md +++ b/packages/rescript-relay/docs/conversion-contract.md @@ -110,7 +110,7 @@ These existing failures remain outside this conversion change. The runtime is tested through both CommonJS and native ESM release modules. Run `yarn test:all` and `yarn test:conversion:mutations` from the package. The mutation check runs isolated copies and requires behavioral test failures for -18 deliberately introduced faults; it does not claim a comprehensive mutation score. +20 deliberately introduced faults; it does not claim a comprehensive mutation score. ## Generated size and sharing @@ -140,3 +140,22 @@ custom scalar paths start inside each result's `value`. Mounted hook tests cover nullable payloads, union/interface payloads, mixed success/error results, store updates, and preservation of the raw Relay store; a typed ReScript helper checks the generated wrapper. + +## Custom scalar ordering follow-up + +`utils-scalar-ordering-tests.js` enumerates all 120 orders of five sibling fields +(single array-backed scalar, scalar list, referenced input, nullable field, and +another scalar), with forward/reversed instruction order, both nullable +directions, and both legacy/prepared runtimes. Each of the 960 combinations runs +twice against frozen input, checking exact callback order/count, result identity, +source preservation, sparse lists, and continued sibling conversion. + +Additional cases distinguish empty array-backed scalars from empty GraphQL +lists; preserve falsey/null/undefined/object/array/Date/option callback results at +root, field, and list positions; and verify that a failing list callback stops +later elements/siblings without poisoning a subsequent call. Mounted compiled +queries select the same mixed scalar/list fields in opposite orders and verify +read conversion, recursive variable serialization, write conversion, nullable +store updates, and raw-store preservation. Targeted mutations explicitly restore +the historical sibling early return and incorrectly normalize scalar results; +both must fail behavioral assertions. diff --git a/packages/rescript-relay/scripts/test-conversion-mutations.js b/packages/rescript-relay/scripts/test-conversion-mutations.js index 0036c9a9..268417ce 100644 --- a/packages/rescript-relay/scripts/test-conversion-mutations.js +++ b/packages/rescript-relay/scripts/test-conversion-mutations.js @@ -19,7 +19,7 @@ const config = { bail: false, collectCoverage: false, roots: [path.join(root, "__tests__")], - testRegex: "/utils-prepared-tests.js$", + testRegex: "/utils-(prepared|scalar-ordering)-tests.js$", }; const faults = [ [ @@ -78,6 +78,16 @@ const faults = [ "convert = callback(node.scalar);", "convert = value => any(callback(node.scalar)(value));", ], + [ + "scalar result nullability", + "convert = callback(node.scalar);", + "convert = value => callback(node.scalar)(value) ?? nullable;", + ], + [ + "early return after converted sibling", + "result[key] = next;\n }\n }", + "result[key] = next;\n }\n if (convert !== undefined) return result === undefined ? value : result;\n }", + ], [ "union ordering", "(children[value.__typename] || any)(union(value))", From 8cb7b989e9939d78f923ade81caf2456c7666490 Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Wed, 23 Sep 2026 11:07:10 +0200 Subject: [PATCH 22/23] Remove unshipped runtime prototype from merge scope --- packages/rescript-relay/benchmarks/README.md | 7 +- .../benchmarks/rescript-runtime/.gitignore | 5 - .../benchmarks/rescript-runtime/README.md | 94 - .../benchmarks/rescript-runtime/build.js | 26 - .../benchmarks/rescript-runtime/compare.js | 95 - .../benchmarks/rescript-runtime/entry.mjs | 5 - .../benchmarks/rescript-runtime/rescript.json | 6 - .../benchmarks/rescript-runtime/resolver.js | 7 - .../results/paired-final.json | 2437 ----------------- .../rescript-runtime/results/size.json | 26 - .../rescript-runtime/results/summary.json | 512 ---- .../benchmarks/rescript-runtime/size.js | 23 - .../src/RescriptRelay_Conversion.res | 312 --- .../src/RescriptRelay_ConversionInterop.res | 109 - .../src/RescriptRelay_LegacyConversion.res | 261 -- .../benchmarks/rescript-runtime/test.js | 31 - 16 files changed, 4 insertions(+), 3952 deletions(-) delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/.gitignore delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/README.md delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/build.js delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/compare.js delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/entry.mjs delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/rescript.json delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/resolver.js delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/results/paired-final.json delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/results/size.json delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/results/summary.json delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/size.js delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_LegacyConversion.res delete mode 100644 packages/rescript-relay/benchmarks/rescript-runtime/test.js diff --git a/packages/rescript-relay/benchmarks/README.md b/packages/rescript-relay/benchmarks/README.md index a1738ca5..6ff292ef 100644 --- a/packages/rescript-relay/benchmarks/README.md +++ b/packages/rescript-relay/benchmarks/README.md @@ -110,6 +110,7 @@ cache or dependency changes were needed. See [bundle-size measurements and budgets](SIZE.md) for complete generated JS, shared/separate bundles, gzip/Brotli reports, and reproduction commands. -See the [ReScript runtime experiment](rescript-runtime/README.md) for a tested -port of both converters, paired timing results, bundle measurements, and the -reason the shipping runtime remains JavaScript. +A ReScript runtime port was evaluated but not adopted: it increased bundle size +and regressed some conversion workloads. The prototype and its measurements remain +available in [the experiment commit](https://github.com/zth/rescript-relay/tree/e1b12c732ea258f338defeed058061e8f78609e4/packages/rescript-relay/benchmarks/rescript-runtime). +The shipping runtime remains JavaScript. diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/.gitignore b/packages/rescript-relay/benchmarks/rescript-runtime/.gitignore deleted file mode 100644 index f0656617..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -lib/ -.rescript* -.bsb.lock -src/*.mjs -output/ diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/README.md b/packages/rescript-relay/benchmarks/rescript-runtime/README.md deleted file mode 100644 index 647f5e80..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/README.md +++ /dev/null @@ -1,94 +0,0 @@ -# ReScript runtime experiment - -Decision: retain the shipping JavaScript runtime. This prototype ports both the -prepared converter and the legacy traversal, but does not preserve performance -across the measured cases and increases runtime bundle size. -The experiment is excluded from the package's ReScript sources and release build. - -The conversion and preparation logic lives in `src/*.res`. Dynamic property -access is isolated in `RescriptRelay_ConversionInterop.res`. Three small raw-JS -object loops preserve allocation-free `for...in` traversal, property order, -metadata handling and lazy copying. ReScript's `Object.keys` alternative allocates -an array for each visited object; the initial direct port was slower. This is -therefore a hybrid port, not an entirely ReScript implementation. - -From `packages/rescript-relay`: - -```sh -node benchmarks/rescript-runtime/build.js -node benchmarks/rescript-runtime/test.js -ENABLE_PERSISTING=true node benchmarks/rescript-runtime/test.js -node benchmarks/conversion.js --prepared --implementation benchmarks/rescript-runtime/output/utils.cjs -node benchmarks/conversion.js --implementation benchmarks/rescript-runtime/output/utils.cjs -node benchmarks/rescript-runtime/compare.js benchmarks/rescript-runtime/output/comparison.json -node benchmarks/rescript-runtime/size.js -``` - -Build with the repository's pinned ReScript and esbuild versions. The standalone -build bundles ESM and derives an equivalent CommonJS export boundary. It does not -add module wrappers or ReScript runtime dependencies to the measured candidate. -Tests resolve the actual shipping `src/utils.js` path to the candidate, including -imports made by compiled ReScript bindings. Native ESM/CommonJS parity is checked -separately. Existing tests remain unchanged. - -## Results and decision (2026-09-22) - -All **243 existing tests pass** against the candidate: 242 main tests in 49 suites, -including the 139 utility tests and mounted Relay integration tests, plus the -separate persisted-query test. Native ESM/CommonJS exports also agree on all -benchmark fixtures in both directions. This establishes useful compatibility -evidence; it is not exhaustive correctness, a new coverage claim, or a completed -production rollout. - -Three runs used Node 24.16.0 on AMD RYZEN AI MAX+ 395, with 31 alternating -baseline/candidate pairs per case. Each pair reverses execution order; calibration -and preparation are outside warm timings. All recorded comparisons use the same fixture -version and the JavaScript runtime from `b0f009a`. The JavaScript runtime has since -been optimized further; check out `3de062b` to reproduce these historical results, -or use the commands above to compare against the current runtime. The shared host was busy, so -small differences and individual timings are noisy. These are conversion -microbenchmarks, not app latency measurements or cross-engine guarantees. - -The range below is the median paired **conversion-time change** in each run -(negative is faster): - -| Case | Prepared port | Legacy port | -| --- | ---: | ---: | -| Small fragment | -16.5% to -8.9% | -3.6% to +0.9% | -| Connection, 100 rows | -21.7% to -17.9% | -3.0% to +0.4% | -| Plural fragment, 100 rows | -19.4% to -12.1% | -7.2% to +4.3% | -| Union list, 100 rows | -22.2% to -18.0% | +0.8% to +5.2% | -| Custom scalar list | -1.8% to +2.2% | +2.5% to +9.6% | -| Opaque JSON list | **+14.0% to +20.0%** | +2.1% to +4.5% | -| Recursive inputs | -14.3% to -2.3% | -4.4% to +4.1% | - -All cases and source hashes are in [summary.json](results/summary.json); the final -run's individual measurements are in [paired-final.json](results/paired-final.json). -Earlier tuning removed most of the legacy port's initial regression by inlining -instruction lookups. Moving the prepared array converter into the preparation -scope did not resolve the opaque-list regression. - -The object-heavy gains do not establish that ReScript itself is faster. The -prototype also specializes generic record traversal to avoid looking up fields -in an empty instruction dictionary, and its compiled generic array traversal is -inlined. Those changes could be investigated independently in JavaScript. - -Equivalent complete ESM runtime bundles, retaining all four public exports and -minified with esbuild 0.25.12: - -| Bytes | JavaScript | Hybrid ReScript | Increase | -| --- | ---: | ---: | ---: | -| Minified | 5,578 | 6,328 | 750 | -| Gzip | 2,238 | 2,638 | **400 (+17.9%)** | -| Brotli | 2,032 | 2,352 | 320 | - -[Size details](results/size.json) also include equivalent CommonJS-entry bundles. -These numbers measure only the shared runtime; compiler-generated instructions -are unchanged. This experiment is not included in the release, so it adds no -production bundle bytes. - -The hybrid approach needs substantial dynamic FFI and handwritten JS object -loops, so it has not clearly simplified maintenance either. Keep the prototype -isolated and retain the already-tested, optimized JavaScript implementation. -Future adoption needs to resolve the regressions, weigh the size/maintenance cost, -and validate supported JS engines; passing the existing tests alone is not enough. diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/build.js b/packages/rescript-relay/benchmarks/rescript-runtime/build.js deleted file mode 100644 index adf73985..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/build.js +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env node -// Standalone experiment: never replaces the shipping runtime or release build. -const fs = require("fs"); -const path = require("path"); -const { spawn } = require("child_process"); -const esbuild = require("esbuild"); -async function build() { - const compiler = path.resolve(__dirname, "../../node_modules/.bin/rescript"); - await new Promise((resolve, reject) => { - const child = spawn(compiler, ["build"], {cwd: __dirname, stdio: "inherit"}); - child.on("error", reject); - child.on("exit", code => code === 0 ? resolve() : reject(new Error(`ReScript exited ${code}`))); - }); - const output = path.join(__dirname, "output"); - await esbuild.build({ - entryPoints: [path.join(__dirname, "entry.mjs")], - bundle: true, - format: "esm", - outfile: path.join(output, "utils.mjs"), - }); - const source = fs.readFileSync(path.join(output, "utils.mjs"), "utf8"); - const boundary = /export \{([\w\s,]+)\};\s*$/; - if (!boundary.test(source)) throw new Error("Unexpected ESM export boundary"); - fs.writeFileSync(path.join(output, "utils.cjs"), source.replace(boundary, "module.exports = {$1};\n")); -} -build().catch(error => {console.error(error); process.exitCode = 1;}); diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/compare.js b/packages/rescript-relay/benchmarks/rescript-runtime/compare.js deleted file mode 100644 index 9a0a6e6a..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/compare.js +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env node -// Alternate order within each pair to reduce temporal bias. These are warm -// microbenchmarks, not end-to-end latency or proof of parity across JS engines. -const {performance} = require("perf_hooks"); -const fs = require("fs"); -const assert = require("assert/strict"); -const os = require("os"); -const crypto = require("crypto"); -const v8 = require("v8"); -const {cases, converters} = require("../fixtures"); -const baseline = require("../../src/utils"); -const candidate = require("./output/utils.cjs"); -const samples = 31; -const targetSampleMs = 20; -let sink; -function batch(convert, root, count) { - const start = performance.now(); - for (let i = 0; i < count; i++) sink = convert(root); - return (performance.now() - start) * 1e6 / count; -} -function median(values) { - return [...values].sort((a, b) => a - b)[Math.floor(values.length / 2)]; -} -function hash(filename) { - return crypto.createHash("sha256") - .update(fs.readFileSync(require.resolve(filename))).digest("hex"); -} -function build(runtime, fixture, mode) { - if (mode === "legacy") { - return value => runtime.traverser(value, fixture.maps, converters, fixture.nullable); - } - if (Object.keys(fixture.plan.roots).length === 1 && fixture.plan.roots.__root.length === 0) { - return value => runtime.convertWithoutPlan(value, fixture.nullable); - } - return runtime.prepareConversion(fixture.plan, converters, fixture.nullable); -} -if (!process.argv[2]) { - throw new Error("Usage: node benchmarks/rescript-runtime/compare.js "); -} -const initialLoad = os.loadavg(); -const results = []; -for (const mode of ["prepared", "legacy"]) { - for (const fixture of cases) { - const before = v8.deserialize(v8.serialize(fixture.root)); - const original = build(baseline, fixture, mode); - const ported = build(candidate, fixture, mode); - assert.deepEqual(ported(fixture.root), original(fixture.root), fixture.name); - let count = 100; - while (Math.min(batch(original, fixture.root, count), batch(ported, fixture.root, count)) * count < targetSampleMs * 1e6) { - count *= 2; - } - const measurements = []; - for (let i = 0; i < samples; i++) { - let baselineNs, candidateNs; - if (i % 2) { - candidateNs = batch(ported, fixture.root, count); - baselineNs = batch(original, fixture.root, count); - } else { - baselineNs = batch(original, fixture.root, count); - candidateNs = batch(ported, fixture.root, count); - } - measurements.push({baselineNs, candidateNs}); - } - assert.deepEqual(fixture.root, before, fixture.name + ": input mutated"); - const result = { - mode, - name: fixture.name, - count, - baselineNs: median(measurements.map(sample => sample.baselineNs)), - candidateNs: median(measurements.map(sample => sample.candidateNs)), - ratio: median(measurements.map(sample => sample.candidateNs / sample.baselineNs)), - samples: measurements, - }; - results.push(result); - console.log(mode, fixture.name, Math.round(result.baselineNs), Math.round(result.candidateNs), (result.ratio * 100 - 100).toFixed(1) + "%"); - } -} -const report = { - fixtureVersion: 3, - node: process.version, - cpu: os.cpus()[0].model, - samples, - targetSampleMs, - initialLoad, - finalLoad: os.loadavg(), - sha256: { - baseline: hash("../../src/utils"), - preparedBaseline: hash("../../src/prepareConversion"), - candidate: hash("./output/utils.cjs"), - fixtures: hash("../fixtures"), - }, - results, -}; -fs.writeFileSync(process.argv[2], JSON.stringify(report, null, 2) + "\n"); -if (!sink) throw new Error("Missing benchmark result"); diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/entry.mjs b/packages/rescript-relay/benchmarks/rescript-runtime/entry.mjs deleted file mode 100644 index 96248862..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/entry.mjs +++ /dev/null @@ -1,5 +0,0 @@ -export {prepareConversion, convertWithoutPlan} from './src/RescriptRelay_Conversion.mjs'; -export {traverser} from './src/RescriptRelay_LegacyConversion.mjs'; -export function runConversion(convert, value) { - return convert(value); -} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/rescript.json b/packages/rescript-relay/benchmarks/rescript-runtime/rescript.json deleted file mode 100644 index 3fc3b7df..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/rescript.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "relay-conversion-runtime-experiment", - "sources": ["src"], - "package-specs": {"module": "esmodule", "in-source": true}, - "suffix": ".mjs" -} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/resolver.js b/packages/rescript-relay/benchmarks/rescript-runtime/resolver.js deleted file mode 100644 index badabc36..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/resolver.js +++ /dev/null @@ -1,7 +0,0 @@ -const path = require("path"); -const runtime = path.resolve(__dirname, "../../src/utils.js"); -const candidate = path.resolve(__dirname, "output/utils.cjs"); -module.exports = (request, options) => { - const resolved = options.defaultResolver(request, options); - return resolved === runtime ? candidate : resolved; -}; diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/results/paired-final.json b/packages/rescript-relay/benchmarks/rescript-runtime/results/paired-final.json deleted file mode 100644 index afb82854..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/results/paired-final.json +++ /dev/null @@ -1,2437 +0,0 @@ -{ - "fixtureVersion": 3, - "node": "v24.16.0", - "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", - "samples": 31, - "targetSampleMs": 20, - "initialLoad": [ - 20.68, - 21.39, - 18.74 - ], - "finalLoad": [ - 19.18, - 20.96, - 18.69 - ], - "sha256": { - "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", - "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", - "candidate": "efdf597c559c9b77f3d07ec1c3887eb37708d373d4f820250af2436ce39a08ea", - "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" - }, - "results": [ - { - "mode": "prepared", - "name": "small fragment", - "count": 409600, - "baselineNs": 102.4374340820311, - "candidateNs": 91.70031738281237, - "ratio": 0.9006024123311214, - "samples": [ - { - "baselineNs": 109.94234130859377, - "candidateNs": 97.37760253906255 - }, - { - "baselineNs": 105.10208984375005, - "candidateNs": 93.7282250976562 - }, - { - "baselineNs": 106.64225830078131, - "candidateNs": 98.2967236328125 - }, - { - "baselineNs": 114.22939941406251, - "candidateNs": 167.64104248046863 - }, - { - "baselineNs": 107.84939697265627, - "candidateNs": 130.96789794921875 - }, - { - "baselineNs": 99.29998535156248, - "candidateNs": 117.90455810546884 - }, - { - "baselineNs": 107.66093017578137, - "candidateNs": 90.97561035156242 - }, - { - "baselineNs": 112.22089111328133, - "candidateNs": 91.4827954101563 - }, - { - "baselineNs": 154.84508056640615, - "candidateNs": 153.66682617187544 - }, - { - "baselineNs": 114.05191406250015, - "candidateNs": 104.93644531249956 - }, - { - "baselineNs": 104.63494628906277, - "candidateNs": 94.05853515625007 - }, - { - "baselineNs": 97.82815917968757, - "candidateNs": 89.56975341796846 - }, - { - "baselineNs": 98.48533691406259, - "candidateNs": 90.70725585937467 - }, - { - "baselineNs": 99.30081787109357, - "candidateNs": 97.82077392578135 - }, - { - "baselineNs": 168.26986816406264, - "candidateNs": 92.43425048828136 - }, - { - "baselineNs": 101.72140869140645, - "candidateNs": 89.448603515625 - }, - { - "baselineNs": 101.05002197265622, - "candidateNs": 91.00589355468702 - }, - { - "baselineNs": 98.11576416015654, - "candidateNs": 89.46132324218759 - }, - { - "baselineNs": 97.67626220703096, - "candidateNs": 87.0336865234378 - }, - { - "baselineNs": 98.87944091796886, - "candidateNs": 91.70031738281237 - }, - { - "baselineNs": 167.2362255859372, - "candidateNs": 98.3479174804691 - }, - { - "baselineNs": 102.95070800781292, - "candidateNs": 91.51691650390647 - }, - { - "baselineNs": 102.4374340820311, - "candidateNs": 92.99651855468773 - }, - { - "baselineNs": 100.45732421875009, - "candidateNs": 90.6966894531247 - }, - { - "baselineNs": 98.08325683593688, - "candidateNs": 88.19584228515586 - }, - { - "baselineNs": 99.61608642578112, - "candidateNs": 87.14471191406227 - }, - { - "baselineNs": 167.0240307617188, - "candidateNs": 88.94359619140647 - }, - { - "baselineNs": 110.56950439453094, - "candidateNs": 95.71288330078143 - }, - { - "baselineNs": 99.8858837890626, - "candidateNs": 94.03823486328177 - }, - { - "baselineNs": 101.0484082031249, - "candidateNs": 91.09568603515639 - }, - { - "baselineNs": 98.72448486328067, - "candidateNs": 88.51991943359282 - } - ] - }, - { - "mode": "prepared", - "name": "unchanged object", - "count": 409600, - "baselineNs": 55.89947509765713, - "candidateNs": 44.29194091796873, - "ratio": 0.7933846994786131, - "samples": [ - { - "baselineNs": 97.59392822265566, - "candidateNs": 44.561713867187215 - }, - { - "baselineNs": 55.46484130859452, - "candidateNs": 45.604702148438484 - }, - { - "baselineNs": 55.130175781249456, - "candidateNs": 44.460349121093756 - }, - { - "baselineNs": 56.38545410156293, - "candidateNs": 44.06798339843809 - }, - { - "baselineNs": 55.0174853515617, - "candidateNs": 46.18489990234398 - }, - { - "baselineNs": 55.83619628906189, - "candidateNs": 43.6313159179691 - }, - { - "baselineNs": 55.53902832031277, - "candidateNs": 43.98212646484434 - }, - { - "baselineNs": 57.06077636718709, - "candidateNs": 43.416262207031096 - }, - { - "baselineNs": 57.15270019531204, - "candidateNs": 43.707045898436775 - }, - { - "baselineNs": 56.14256347656221, - "candidateNs": 44.2775097656245 - }, - { - "baselineNs": 55.40562255859416, - "candidateNs": 43.805034179688064 - }, - { - "baselineNs": 103.50011230468748, - "candidateNs": 44.71405273437479 - }, - { - "baselineNs": 62.32186767578196, - "candidateNs": 44.296611328125124 - }, - { - "baselineNs": 54.531901855467964, - "candidateNs": 43.81775390625009 - }, - { - "baselineNs": 54.96553466796783, - "candidateNs": 44.25605712890634 - }, - { - "baselineNs": 54.822585449219034, - "candidateNs": 44.90875488281309 - }, - { - "baselineNs": 55.98484375000101, - "candidateNs": 44.41835205078126 - }, - { - "baselineNs": 55.89947509765713, - "candidateNs": 45.59667724609362 - }, - { - "baselineNs": 58.67748046875065, - "candidateNs": 44.16139648437567 - }, - { - "baselineNs": 53.94333740234459, - "candidateNs": 46.04916748046972 - }, - { - "baselineNs": 56.24348388671874, - "candidateNs": 44.03249023437472 - }, - { - "baselineNs": 54.03738769531264, - "candidateNs": 44.078181152342744 - }, - { - "baselineNs": 54.60914550781237, - "candidateNs": 45.171850585937754 - }, - { - "baselineNs": 82.48651855468746, - "candidateNs": 76.32164306640598 - }, - { - "baselineNs": 54.724963378905976, - "candidateNs": 44.29194091796873 - }, - { - "baselineNs": 54.55870849609301, - "candidateNs": 43.94565673828011 - }, - { - "baselineNs": 56.13421875000135, - "candidateNs": 44.53603027343655 - }, - { - "baselineNs": 54.95953857421965, - "candidateNs": 43.217570800782035 - }, - { - "baselineNs": 57.821540527343004, - "candidateNs": 45.01643066406436 - }, - { - "baselineNs": 56.61731201171971, - "candidateNs": 51.750031738280185 - }, - { - "baselineNs": 56.09936523437442, - "candidateNs": 43.87711914062509 - } - ] - }, - { - "mode": "prepared", - "name": "nullable query", - "count": 204800, - "baselineNs": 148.93603515625298, - "candidateNs": 123.57809570312739, - "ratio": 0.8220193300149227, - "samples": [ - { - "baselineNs": 137.85943847656412, - "candidateNs": 161.1355566406214 - }, - { - "baselineNs": 141.3651855468734, - "candidateNs": 182.12513183593958 - }, - { - "baselineNs": 141.24527832031663, - "candidateNs": 115.42738769531269 - }, - { - "baselineNs": 144.36205566406014, - "candidateNs": 116.54943847656085 - }, - { - "baselineNs": 146.07208007812568, - "candidateNs": 113.64991210937701 - }, - { - "baselineNs": 189.08580078125237, - "candidateNs": 127.03736816406241 - }, - { - "baselineNs": 153.34236328125252, - "candidateNs": 124.94743652343932 - }, - { - "baselineNs": 148.20183593749815, - "candidateNs": 127.25051757812356 - }, - { - "baselineNs": 152.25926269531342, - "candidateNs": 123.57809570312739 - }, - { - "baselineNs": 253.0050927734351, - "candidateNs": 114.87795898437625 - }, - { - "baselineNs": 158.63689453125218, - "candidateNs": 116.46851562499894 - }, - { - "baselineNs": 154.48460937500298, - "candidateNs": 117.33979003906381 - }, - { - "baselineNs": 152.54422363280895, - "candidateNs": 115.03123046874731 - }, - { - "baselineNs": 145.42803710937412, - "candidateNs": 115.33165039062433 - }, - { - "baselineNs": 143.7753515624962, - "candidateNs": 118.1861181640631 - }, - { - "baselineNs": 152.97956542968726, - "candidateNs": 116.4766894531244 - }, - { - "baselineNs": 145.8647021484394, - "candidateNs": 125.69714355468608 - }, - { - "baselineNs": 145.01812988281236, - "candidateNs": 122.22926269531254 - }, - { - "baselineNs": 211.81381347656458, - "candidateNs": 171.66987304687353 - }, - { - "baselineNs": 142.65536621093756, - "candidateNs": 126.83263671875 - }, - { - "baselineNs": 138.2356835937504, - "candidateNs": 112.17133300781333 - }, - { - "baselineNs": 140.00885742187384, - "candidateNs": 116.64404785156623 - }, - { - "baselineNs": 148.62758789062624, - "candidateNs": 155.63967285156187 - }, - { - "baselineNs": 166.79527832031306, - "candidateNs": 113.57109863281423 - }, - { - "baselineNs": 152.78618652343923, - "candidateNs": 126.67677734374827 - }, - { - "baselineNs": 146.36462402343398, - "candidateNs": 123.19519531249767 - }, - { - "baselineNs": 148.93603515625298, - "candidateNs": 157.4605908203086 - }, - { - "baselineNs": 150.28032714843764, - "candidateNs": 191.7699218750002 - }, - { - "baselineNs": 167.9802783203099, - "candidateNs": 144.6338574218764 - }, - { - "baselineNs": 150.73587402343767, - "candidateNs": 137.21172363281298 - }, - { - "baselineNs": 151.84823242187394, - "candidateNs": 125.80442871093834 - } - ] - }, - { - "mode": "prepared", - "name": "connection / 100 rows", - "count": 1600, - "baselineNs": 21940.737499999726, - "candidateNs": 18028.042500000083, - "ratio": 0.8210054435040013, - "samples": [ - { - "baselineNs": 20359.61812500034, - "candidateNs": 20860.72124999987 - }, - { - "baselineNs": 30255.709374999926, - "candidateNs": 17592.882499999974 - }, - { - "baselineNs": 25797.633750000274, - "candidateNs": 16821.530624999923 - }, - { - "baselineNs": 19738.913125000297, - "candidateNs": 16933.64875000043 - }, - { - "baselineNs": 19941.835000000196, - "candidateNs": 18425.186874999894 - }, - { - "baselineNs": 19420.26124999984, - "candidateNs": 17148.7806250002 - }, - { - "baselineNs": 19520.206249999886, - "candidateNs": 17446.70625000026 - }, - { - "baselineNs": 19488.885000000097, - "candidateNs": 16195.704374999877 - }, - { - "baselineNs": 19489.285624999866, - "candidateNs": 16682.881249999467 - }, - { - "baselineNs": 26959.892500000253, - "candidateNs": 16328.54312500001 - }, - { - "baselineNs": 29504.78374999989, - "candidateNs": 18028.042500000083 - }, - { - "baselineNs": 21151.183124999876, - "candidateNs": 16589.39250000003 - }, - { - "baselineNs": 20723.862500000225, - "candidateNs": 20350.406874999862 - }, - { - "baselineNs": 21940.737499999726, - "candidateNs": 18964.62499999984 - }, - { - "baselineNs": 20425.82437500016, - "candidateNs": 17016.50562499992 - }, - { - "baselineNs": 20026.38187499997, - "candidateNs": 16858.21312499968 - }, - { - "baselineNs": 19837.75062500001, - "candidateNs": 16286.901249999913 - }, - { - "baselineNs": 48972.81062500042, - "candidateNs": 16388.71875000007 - }, - { - "baselineNs": 20970.647500000152, - "candidateNs": 16259.862499999825 - }, - { - "baselineNs": 21309.43187500009, - "candidateNs": 16203.224375000218 - }, - { - "baselineNs": 20748.020624999983, - "candidateNs": 23270.93312499983 - }, - { - "baselineNs": 29345.27000000003, - "candidateNs": 21307.96625000016 - }, - { - "baselineNs": 24612.93812500003, - "candidateNs": 21998.778125000055 - }, - { - "baselineNs": 25418.040625000343, - "candidateNs": 22301.012500000183 - }, - { - "baselineNs": 32679.628125000025, - "candidateNs": 25176.7537500001 - }, - { - "baselineNs": 30602.909374999857, - "candidateNs": 24613.814374999947 - }, - { - "baselineNs": 29983.933125000134, - "candidateNs": 25708.765624999614 - }, - { - "baselineNs": 29028.239374999885, - "candidateNs": 20078.14812499987 - }, - { - "baselineNs": 30743.42499999943, - "candidateNs": 20474.741874999156 - }, - { - "baselineNs": 31063.25437500004, - "candidateNs": 20345.54125 - }, - { - "baselineNs": 37214.77437499971, - "candidateNs": 22552.487499999643 - } - ] - }, - { - "mode": "prepared", - "name": "plural fragment / 100 rows", - "count": 1600, - "baselineNs": 15024.559375000308, - "candidateNs": 12962.843749999138, - "ratio": 0.8388993027599011, - "samples": [ - { - "baselineNs": 20039.65687499999, - "candidateNs": 16424.23624999992 - }, - { - "baselineNs": 20096.51437499997, - "candidateNs": 17686.11437499999 - }, - { - "baselineNs": 24327.598749999877, - "candidateNs": 15444.076874999837 - }, - { - "baselineNs": 15024.559375000308, - "candidateNs": 13197.688125000013 - }, - { - "baselineNs": 15903.013125000598, - "candidateNs": 12979.050000000141 - }, - { - "baselineNs": 32338.839999999895, - "candidateNs": 18736.60000000086 - }, - { - "baselineNs": 14792.79687500025, - "candidateNs": 12825.772499999175 - }, - { - "baselineNs": 15493.864999999689, - "candidateNs": 14616.638124999781 - }, - { - "baselineNs": 14846.178125000051, - "candidateNs": 12237.898749999658 - }, - { - "baselineNs": 15038.228749999687, - "candidateNs": 13266.411250000376 - }, - { - "baselineNs": 15038.053750000698, - "candidateNs": 13986.153124999419 - }, - { - "baselineNs": 16505.4525000005, - "candidateNs": 14472.1281249997 - }, - { - "baselineNs": 17360.468125000352, - "candidateNs": 12917.051250000215 - }, - { - "baselineNs": 15566.8656250009, - "candidateNs": 13091.230625000208 - }, - { - "baselineNs": 14664.346875000547, - "candidateNs": 13486.759375000474 - }, - { - "baselineNs": 26451.34437500019, - "candidateNs": 12058.772499999577 - }, - { - "baselineNs": 20010.4518750004, - "candidateNs": 12298.870624999838 - }, - { - "baselineNs": 14235.004375000244, - "candidateNs": 12233.377500000415 - }, - { - "baselineNs": 14404.982500000186, - "candidateNs": 13817.790624999589 - }, - { - "baselineNs": 14016.360000000532, - "candidateNs": 11580.362500000094 - }, - { - "baselineNs": 14522.705000000542, - "candidateNs": 12023.437500000682 - }, - { - "baselineNs": 13868.424374999222, - "candidateNs": 11688.829375000296 - }, - { - "baselineNs": 14863.53000000008, - "candidateNs": 11776.28249999998 - }, - { - "baselineNs": 14366.264999999887, - "candidateNs": 11842.851874999951 - }, - { - "baselineNs": 14165.13499999951, - "candidateNs": 11883.12187499946 - }, - { - "baselineNs": 14031.645625000237, - "candidateNs": 11743.420625000454 - }, - { - "baselineNs": 18998.802500000238, - "candidateNs": 23991.037499999948 - }, - { - "baselineNs": 15176.671875000238, - "candidateNs": 18113.32187499943 - }, - { - "baselineNs": 14734.148124999821, - "candidateNs": 12041.689999999791 - }, - { - "baselineNs": 14541.93499999974, - "candidateNs": 12962.843749999138 - }, - { - "baselineNs": 14179.568749999591, - "candidateNs": 11785.236875000463 - } - ] - }, - { - "mode": "prepared", - "name": "union list / 100 rows", - "count": 1600, - "baselineNs": 18634.26312499996, - "candidateNs": 14601.722500000276, - "ratio": 0.8197016737223956, - "samples": [ - { - "baselineNs": 18972.52750000007, - "candidateNs": 14239.913750000142 - }, - { - "baselineNs": 18421.379999999772, - "candidateNs": 14838.044374999981 - }, - { - "baselineNs": 18617.475000000923, - "candidateNs": 14360.341875000131 - }, - { - "baselineNs": 24171.028125000474, - "candidateNs": 22540.9406250003 - }, - { - "baselineNs": 18653.66250000079, - "candidateNs": 14359.558749999904 - }, - { - "baselineNs": 19526.386874999844, - "candidateNs": 14505.17125000033 - }, - { - "baselineNs": 24572.761874999287, - "candidateNs": 13988.295000000335 - }, - { - "baselineNs": 18628.120624999836, - "candidateNs": 14459.065624999994 - }, - { - "baselineNs": 18279.718124999818, - "candidateNs": 16714.15937500001 - }, - { - "baselineNs": 16520.76875000034, - "candidateNs": 14681.273125000871 - }, - { - "baselineNs": 17573.92125000024, - "candidateNs": 14993.10625000021 - }, - { - "baselineNs": 19809.47812499949, - "candidateNs": 16282.743749999327 - }, - { - "baselineNs": 22875.159374999614, - "candidateNs": 25305.784999999334 - }, - { - "baselineNs": 16622.71124999961, - "candidateNs": 14798.181249999516 - }, - { - "baselineNs": 16422.9899999998, - "candidateNs": 14507.588124999984 - }, - { - "baselineNs": 19595.85500000003, - "candidateNs": 15897.615625000299 - }, - { - "baselineNs": 19145.53562500032, - "candidateNs": 14096.392500000547 - }, - { - "baselineNs": 18500.422500000015, - "candidateNs": 14204.102500000317 - }, - { - "baselineNs": 18940.792500000043, - "candidateNs": 14565.448125000556 - }, - { - "baselineNs": 17199.41375000076, - "candidateNs": 14878.65250000027 - }, - { - "baselineNs": 17673.853750000035, - "candidateNs": 14487.287499999866 - }, - { - "baselineNs": 32536.432499999817, - "candidateNs": 15202.458124999794 - }, - { - "baselineNs": 19627.960000000257, - "candidateNs": 17209.858749999967 - }, - { - "baselineNs": 16889.121250000015, - "candidateNs": 14601.722500000276 - }, - { - "baselineNs": 19568.50374999931, - "candidateNs": 15149.107500000127 - }, - { - "baselineNs": 18684.332499999527, - "candidateNs": 14591.127499999177 - }, - { - "baselineNs": 18634.26312499996, - "candidateNs": 14460.824999999886 - }, - { - "baselineNs": 16880.49812500026, - "candidateNs": 14673.126875001117 - }, - { - "baselineNs": 16776.232500000104, - "candidateNs": 14197.414999999864 - }, - { - "baselineNs": 16943.473750000067, - "candidateNs": 14232.80624999961 - }, - { - "baselineNs": 20294.88937499991, - "candidateNs": 27976.244374999624 - } - ] - }, - { - "mode": "prepared", - "name": "custom scalar list", - "count": 3200, - "baselineNs": 11663.735624999845, - "candidateNs": 11913.714062499706, - "ratio": 1.02246230509656, - "samples": [ - { - "baselineNs": 13104.420937499981, - "candidateNs": 11844.64593750022 - }, - { - "baselineNs": 11714.271562499902, - "candidateNs": 12057.946250000101 - }, - { - "baselineNs": 11771.652187500196, - "candidateNs": 13509.677499999954 - }, - { - "baselineNs": 15195.369687500033, - "candidateNs": 13185.261250000054 - }, - { - "baselineNs": 14034.475625000481, - "candidateNs": 12021.132812500355 - }, - { - "baselineNs": 11663.735624999845, - "candidateNs": 11640.181562500515 - }, - { - "baselineNs": 12445.168749999879, - "candidateNs": 12728.162812500159 - }, - { - "baselineNs": 11562.89500000014, - "candidateNs": 11759.804375000158 - }, - { - "baselineNs": 11526.291562500433, - "candidateNs": 11657.163749999881 - }, - { - "baselineNs": 11332.105312500289, - "candidateNs": 11591.636874999835 - }, - { - "baselineNs": 17037.895937500027, - "candidateNs": 12781.091250000145 - }, - { - "baselineNs": 11296.619999999963, - "candidateNs": 11550.368124999863 - }, - { - "baselineNs": 11609.12906250019, - "candidateNs": 11645.119062500271 - }, - { - "baselineNs": 11484.455937500117, - "candidateNs": 11906.331562499872 - }, - { - "baselineNs": 11606.777812500013, - "candidateNs": 11765.534062500366 - }, - { - "baselineNs": 11833.910312499826, - "candidateNs": 11784.28218750014 - }, - { - "baselineNs": 11672.536562500114, - "candidateNs": 18533.369374999893 - }, - { - "baselineNs": 11586.223437499826, - "candidateNs": 13151.350312500086 - }, - { - "baselineNs": 12050.904687499722, - "candidateNs": 11913.714062499706 - }, - { - "baselineNs": 11367.700937499876, - "candidateNs": 11716.535312500015 - }, - { - "baselineNs": 11413.97281249965, - "candidateNs": 12370.092499999713 - }, - { - "baselineNs": 11358.871874999748, - "candidateNs": 12500.83625000002 - }, - { - "baselineNs": 11260.072499999866, - "candidateNs": 11864.351875000237 - }, - { - "baselineNs": 11414.27031250032, - "candidateNs": 18651.317187499786 - }, - { - "baselineNs": 12318.707499999846, - "candidateNs": 11815.597500000196 - }, - { - "baselineNs": 11238.465937499881, - "candidateNs": 11880.062812500115 - }, - { - "baselineNs": 11319.168750000017, - "candidateNs": 11492.680937500381 - }, - { - "baselineNs": 11977.907500000241, - "candidateNs": 12307.007499999827 - }, - { - "baselineNs": 11681.52531249973, - "candidateNs": 12489.1018750003 - }, - { - "baselineNs": 15664.077499999963, - "candidateNs": 15516.251250000438 - }, - { - "baselineNs": 14271.038437499898, - "candidateNs": 13638.790312500078 - } - ] - }, - { - "mode": "prepared", - "name": "opaque JSON list", - "count": 51200, - "baselineNs": 441.32806640622135, - "candidateNs": 538.5150781249947, - "ratio": 1.2004831145919181, - "samples": [ - { - "baselineNs": 440.8327929687772, - "candidateNs": 523.2655468750024 - }, - { - "baselineNs": 439.28455078123824, - "candidateNs": 511.2383203125148 - }, - { - "baselineNs": 433.41644531249557, - "candidateNs": 520.7713867187281 - }, - { - "baselineNs": 420.8522656249869, - "candidateNs": 518.2329882812198 - }, - { - "baselineNs": 441.32806640622135, - "candidateNs": 592.3081640624872 - }, - { - "baselineNs": 464.08630859374966, - "candidateNs": 662.4395312500296 - }, - { - "baselineNs": 435.6812500000018, - "candidateNs": 526.524062500009 - }, - { - "baselineNs": 436.83011718751885, - "candidateNs": 527.8083203124951 - }, - { - "baselineNs": 434.536718749996, - "candidateNs": 547.9375781249729 - }, - { - "baselineNs": 465.4555078125, - "candidateNs": 534.9953320312295 - }, - { - "baselineNs": 459.19171874999165, - "candidateNs": 555.1512109374812 - }, - { - "baselineNs": 469.99748046872014, - "candidateNs": 569.3426757812503 - }, - { - "baselineNs": 469.4278515624717, - "candidateNs": 552.409707031245 - }, - { - "baselineNs": 512.0644921874984, - "candidateNs": 563.0489453124809 - }, - { - "baselineNs": 601.2666796874911, - "candidateNs": 706.9292773437396 - }, - { - "baselineNs": 457.85929687500726, - "candidateNs": 573.1299218750152 - }, - { - "baselineNs": 479.8366015625177, - "candidateNs": 587.9066601562499 - }, - { - "baselineNs": 518.061953125013, - "candidateNs": 600.2937695312482 - }, - { - "baselineNs": 519.6924023437432, - "candidateNs": 626.7192773437813 - }, - { - "baselineNs": 485.5620507812475, - "candidateNs": 613.0240625000027 - }, - { - "baselineNs": 474.68564453126305, - "candidateNs": 564.886406250018 - }, - { - "baselineNs": 440.98171874999537, - "candidateNs": 509.18757812500104 - }, - { - "baselineNs": 436.0827929687616, - "candidateNs": 538.5150781249947 - }, - { - "baselineNs": 614.3081249999938, - "candidateNs": 617.4286718749755 - }, - { - "baselineNs": 465.15533203123744, - "candidateNs": 510.7692773437477 - }, - { - "baselineNs": 425.8499999999898, - "candidateNs": 518.2672460937355 - }, - { - "baselineNs": 427.6052539062647, - "candidateNs": 511.00058593746667 - }, - { - "baselineNs": 434.6862109374782, - "candidateNs": 505.33478515625063 - }, - { - "baselineNs": 429.09968749999194, - "candidateNs": 505.5398632812569 - }, - { - "baselineNs": 424.09548828121757, - "candidateNs": 509.11947265621643 - }, - { - "baselineNs": 439.968261718775, - "candidateNs": 505.98777343751067 - } - ] - }, - { - "mode": "prepared", - "name": "recursive inputs", - "count": 1600, - "baselineNs": 16857.66187499894, - "candidateNs": 14194.308749999891, - "ratio": 0.8569818680573524, - "samples": [ - { - "baselineNs": 24157.3268749994, - "candidateNs": 22282.502499999733 - }, - { - "baselineNs": 17043.03062500003, - "candidateNs": 14627.23937499959 - }, - { - "baselineNs": 19114.10124999975, - "candidateNs": 14265.355625000211 - }, - { - "baselineNs": 16303.789374999269, - "candidateNs": 13972.051875000489 - }, - { - "baselineNs": 17096.268749999126, - "candidateNs": 15072.40000000138 - }, - { - "baselineNs": 16586.98749999985, - "candidateNs": 14602.599375000409 - }, - { - "baselineNs": 17052.178750000166, - "candidateNs": 15891.57937500204 - }, - { - "baselineNs": 19432.803125000646, - "candidateNs": 16284.446875001777 - }, - { - "baselineNs": 17408.614999999372, - "candidateNs": 14927.645000000211 - }, - { - "baselineNs": 29361.619374999464, - "candidateNs": 17280.510625000716 - }, - { - "baselineNs": 19070.424999999886, - "candidateNs": 14151.302500001748 - }, - { - "baselineNs": 16004.850000001625, - "candidateNs": 14194.308749999891 - }, - { - "baselineNs": 17173.871874999804, - "candidateNs": 14132.18499999857 - }, - { - "baselineNs": 16524.51312500034, - "candidateNs": 13603.072500000053 - }, - { - "baselineNs": 16404.642499999227, - "candidateNs": 14209.850624999945 - }, - { - "baselineNs": 15866.406874999939, - "candidateNs": 14147.319999999581 - }, - { - "baselineNs": 15889.105624999047, - "candidateNs": 13624.331875000737 - }, - { - "baselineNs": 16058.751250000114, - "candidateNs": 13654.300625000815 - }, - { - "baselineNs": 15863.269374999618, - "candidateNs": 13812.643750000007 - }, - { - "baselineNs": 24910.675625001208, - "candidateNs": 22387.08062500109 - }, - { - "baselineNs": 16172.58562500183, - "candidateNs": 13524.937499998941 - }, - { - "baselineNs": 16109.847499999432, - "candidateNs": 13677.545000000464 - }, - { - "baselineNs": 16171.119999999064, - "candidateNs": 13502.833125000961 - }, - { - "baselineNs": 17074.35250000117, - "candidateNs": 14573.694375001196 - }, - { - "baselineNs": 17343.924374999915, - "candidateNs": 14163.738750000903 - }, - { - "baselineNs": 16857.66187499894, - "candidateNs": 13778.541874999064 - }, - { - "baselineNs": 16494.693750000806, - "candidateNs": 13728.209374999096 - }, - { - "baselineNs": 16570.07437499942, - "candidateNs": 13386.175625000758 - }, - { - "baselineNs": 17378.471249999166, - "candidateNs": 20003.506875000312 - }, - { - "baselineNs": 16931.557500001873, - "candidateNs": 25859.69999999861 - }, - { - "baselineNs": 16685.373124998932, - "candidateNs": 15307.688124999004 - } - ] - }, - { - "mode": "legacy", - "name": "small fragment", - "count": 102400, - "baselineNs": 263.53763671874475, - "candidateNs": 255.13298828126807, - "ratio": 0.9817418609062459, - "samples": [ - { - "baselineNs": 258.73941406249656, - "candidateNs": 244.9315722656209 - }, - { - "baselineNs": 266.5002832031149, - "candidateNs": 246.17386718752243 - }, - { - "baselineNs": 264.80283203127897, - "candidateNs": 251.48429687501306 - }, - { - "baselineNs": 253.63826171872716, - "candidateNs": 251.6994531250205 - }, - { - "baselineNs": 249.48050781247844, - "candidateNs": 252.37386718750088 - }, - { - "baselineNs": 280.17132812500734, - "candidateNs": 462.2243945312477 - }, - { - "baselineNs": 250.23300781249702, - "candidateNs": 245.664218750008 - }, - { - "baselineNs": 259.3158984375066, - "candidateNs": 239.8107714843789 - }, - { - "baselineNs": 254.9596093749784, - "candidateNs": 246.0752441406555 - }, - { - "baselineNs": 255.7985937500007, - "candidateNs": 246.2135937500065 - }, - { - "baselineNs": 256.5203710937425, - "candidateNs": 255.13298828126807 - }, - { - "baselineNs": 300.71591796872355, - "candidateNs": 297.79379882810986 - }, - { - "baselineNs": 260.60906249998794, - "candidateNs": 262.29780273439474 - }, - { - "baselineNs": 348.1220214844072, - "candidateNs": 252.86914062498056 - }, - { - "baselineNs": 435.9715625000149, - "candidateNs": 251.33108398438964 - }, - { - "baselineNs": 263.2776855468677, - "candidateNs": 260.92156249998055 - }, - { - "baselineNs": 260.4179785156191, - "candidateNs": 257.34752929690075 - }, - { - "baselineNs": 263.53763671874475, - "candidateNs": 261.171455078113 - }, - { - "baselineNs": 265.36472656250254, - "candidateNs": 253.7844433593861 - }, - { - "baselineNs": 261.387578125003, - "candidateNs": 256.28566406247444 - }, - { - "baselineNs": 266.49058593751107, - "candidateNs": 260.13903320311726 - }, - { - "baselineNs": 272.0723339843545, - "candidateNs": 276.69855468751337 - }, - { - "baselineNs": 279.7933593749846, - "candidateNs": 343.9171972656041 - }, - { - "baselineNs": 266.836464843756, - "candidateNs": 413.6512402343939 - }, - { - "baselineNs": 286.5626074218852, - "candidateNs": 268.6473046875193 - }, - { - "baselineNs": 270.45736328123127, - "candidateNs": 314.12964843749336 - }, - { - "baselineNs": 259.6044238281081, - "candidateNs": 252.11410156252612 - }, - { - "baselineNs": 269.32924804686564, - "candidateNs": 252.63666015625574 - }, - { - "baselineNs": 266.77951171876657, - "candidateNs": 268.0229785156385 - }, - { - "baselineNs": 262.2950585937289, - "candidateNs": 267.26451171875 - }, - { - "baselineNs": 260.709345703134, - "candidateNs": 244.45499999998788 - } - ] - }, - { - "mode": "legacy", - "name": "unchanged object", - "count": 102400, - "baselineNs": 111.38375976564419, - "candidateNs": 110.24087890621814, - "ratio": 0.9926745976948665, - "samples": [ - { - "baselineNs": 144.83859374998076, - "candidateNs": 112.44680664063365 - }, - { - "baselineNs": 108.16928710937646, - "candidateNs": 109.61136718748321 - }, - { - "baselineNs": 114.8605468750219, - "candidateNs": 112.46491210936682 - }, - { - "baselineNs": 112.7108789062703, - "candidateNs": 114.32193359372178 - }, - { - "baselineNs": 112.51381835936769, - "candidateNs": 111.68960937499861 - }, - { - "baselineNs": 122.57160156249114, - "candidateNs": 124.43147460935222 - }, - { - "baselineNs": 112.95890625000027, - "candidateNs": 109.3335937499873 - }, - { - "baselineNs": 110.64398437500955, - "candidateNs": 109.21041015624411 - }, - { - "baselineNs": 111.80575195311349, - "candidateNs": 110.02464843748783 - }, - { - "baselineNs": 109.44542968751136, - "candidateNs": 110.24087890621814 - }, - { - "baselineNs": 107.82263671874404, - "candidateNs": 108.3128222656171 - }, - { - "baselineNs": 107.91734375001028, - "candidateNs": 108.99722656247944 - }, - { - "baselineNs": 122.71630859377325, - "candidateNs": 113.26573242186554 - }, - { - "baselineNs": 111.38375976564419, - "candidateNs": 112.89500976563005 - }, - { - "baselineNs": 114.41077148436563, - "candidateNs": 108.87452148434562 - }, - { - "baselineNs": 109.25982421873925, - "candidateNs": 109.04251953125055 - }, - { - "baselineNs": 109.45110351560317, - "candidateNs": 110.43323242187597 - }, - { - "baselineNs": 110.50504882813783, - "candidateNs": 108.61622070311938 - }, - { - "baselineNs": 118.52616210937583, - "candidateNs": 109.63386718749746 - }, - { - "baselineNs": 152.42979492189335, - "candidateNs": 109.96721679688905 - }, - { - "baselineNs": 197.68701171873462, - "candidateNs": 200.8624511718793 - }, - { - "baselineNs": 110.58821289061882, - "candidateNs": 129.6916113281199 - }, - { - "baselineNs": 111.37916015623972, - "candidateNs": 108.95182617186805 - }, - { - "baselineNs": 109.80802734376738, - "candidateNs": 110.33050781250607 - }, - { - "baselineNs": 109.42449218749317, - "candidateNs": 108.56583984374168 - }, - { - "baselineNs": 109.82319335937518, - "candidateNs": 109.4253710937565 - }, - { - "baselineNs": 114.26879882812102, - "candidateNs": 109.16022460936148 - }, - { - "baselineNs": 112.32156249999292, - "candidateNs": 110.52647460939369 - }, - { - "baselineNs": 113.92440429688122, - "candidateNs": 110.39712890624997 - }, - { - "baselineNs": 110.16446289062287, - "candidateNs": 115.51373046874147 - }, - { - "baselineNs": 109.84550781248714, - "candidateNs": 110.30437500000545 - } - ] - }, - { - "mode": "legacy", - "name": "nullable query", - "count": 102400, - "baselineNs": 446.55356445311156, - "candidateNs": 429.20505859374464, - "ratio": 0.9638199985851299, - "samples": [ - { - "baselineNs": 395.9141015625178, - "candidateNs": 500.8427929687542 - }, - { - "baselineNs": 395.90452148438254, - "candidateNs": 454.76860351563175 - }, - { - "baselineNs": 390.12787109374614, - "candidateNs": 384.7616796874931 - }, - { - "baselineNs": 393.50799804690695, - "candidateNs": 378.6349609374895 - }, - { - "baselineNs": 403.234384765625, - "candidateNs": 386.5271289062733 - }, - { - "baselineNs": 389.8585253906006, - "candidateNs": 378.15857421875876 - }, - { - "baselineNs": 389.396123046879, - "candidateNs": 461.2721093749883 - }, - { - "baselineNs": 397.21392578126574, - "candidateNs": 505.68642578127765 - }, - { - "baselineNs": 436.4853222656251, - "candidateNs": 382.2343457031252 - }, - { - "baselineNs": 415.46815429690304, - "candidateNs": 390.53617187502 - }, - { - "baselineNs": 406.281845703127, - "candidateNs": 405.21411132814933 - }, - { - "baselineNs": 449.9030566406148, - "candidateNs": 448.0689257812643 - }, - { - "baselineNs": 575.597177734366, - "candidateNs": 645.3925585937625 - }, - { - "baselineNs": 594.3539062499781, - "candidateNs": 432.7214648437305 - }, - { - "baselineNs": 495.794384765631, - "candidateNs": 452.2268945312291 - }, - { - "baselineNs": 542.0296191406493, - "candidateNs": 478.563974609365 - }, - { - "baselineNs": 468.6770214843605, - "candidateNs": 414.27458984372834 - }, - { - "baselineNs": 538.2812304687334, - "candidateNs": 565.4698242187806 - }, - { - "baselineNs": 430.0137109375157, - "candidateNs": 574.8401757812261 - }, - { - "baselineNs": 527.513808593767, - "candidateNs": 426.66050781249965 - }, - { - "baselineNs": 478.1846386718769, - "candidateNs": 408.0650000000219 - }, - { - "baselineNs": 609.4815234374806, - "candidateNs": 456.0169628906153 - }, - { - "baselineNs": 872.3532617187501, - "candidateNs": 423.7497265625123 - }, - { - "baselineNs": 490.43357421872713, - "candidateNs": 396.06096679687397 - }, - { - "baselineNs": 502.96819335937215, - "candidateNs": 413.76845703123166 - }, - { - "baselineNs": 446.55356445311156, - "candidateNs": 430.3972558593827 - }, - { - "baselineNs": 478.1127246093675, - "candidateNs": 392.86733398434137 - }, - { - "baselineNs": 519.2032812500003, - "candidateNs": 500.5407617187529 - }, - { - "baselineNs": 417.30708007811756, - "candidateNs": 435.14147460939506 - }, - { - "baselineNs": 432.7241113281133, - "candidateNs": 429.20505859374464 - }, - { - "baselineNs": 404.2670019531158, - "candidateNs": 395.92781250000536 - } - ] - }, - { - "mode": "legacy", - "name": "connection / 100 rows", - "count": 400, - "baselineNs": 64871.20750000031, - "candidateNs": 65180.14249999396, - "ratio": 1.0035241512219875, - "samples": [ - { - "baselineNs": 63230.53250000157, - "candidateNs": 61696.60749999821 - }, - { - "baselineNs": 106962.43749999667, - "candidateNs": 91770.22249999936 - }, - { - "baselineNs": 73929.72999999984, - "candidateNs": 65936.46999999692 - }, - { - "baselineNs": 64545.067500002915, - "candidateNs": 63723.68749999623 - }, - { - "baselineNs": 67135.76249999278, - "candidateNs": 64125.897499998246 - }, - { - "baselineNs": 64088.980000005904, - "candidateNs": 64585.34250000412 - }, - { - "baselineNs": 63144.192500003555, - "candidateNs": 64289.85999999896 - }, - { - "baselineNs": 62675.20750000586, - "candidateNs": 64724.4799999953 - }, - { - "baselineNs": 63325.287499992555, - "candidateNs": 62852.592499993996 - }, - { - "baselineNs": 61378.48000000304, - "candidateNs": 62256.36750000376 - }, - { - "baselineNs": 69902.51749999516, - "candidateNs": 104747.2474999995 - }, - { - "baselineNs": 63682.45999999999, - "candidateNs": 78835.97750000263 - }, - { - "baselineNs": 64362.019999998665, - "candidateNs": 61801.682499999515 - }, - { - "baselineNs": 61815.03249999878, - "candidateNs": 63428.68000000635 - }, - { - "baselineNs": 64746.172499999375, - "candidateNs": 64082.917499999894 - }, - { - "baselineNs": 62208.72500000041, - "candidateNs": 64151.99750000283 - }, - { - "baselineNs": 63352.034999998075, - "candidateNs": 64024.40750000096 - }, - { - "baselineNs": 64871.20750000031, - "candidateNs": 63776.51499999956 - }, - { - "baselineNs": 62714.9074999943, - "candidateNs": 63592.34249999645 - }, - { - "baselineNs": 87055.98749999808, - "candidateNs": 65180.14249999396 - }, - { - "baselineNs": 128476.62500000297, - "candidateNs": 69677.16499999369 - }, - { - "baselineNs": 64314.45500000336, - "candidateNs": 65291.47750000448 - }, - { - "baselineNs": 67812.51749999683, - "candidateNs": 73623.82749999597 - }, - { - "baselineNs": 77331.20750000126, - "candidateNs": 72873.33250000302 - }, - { - "baselineNs": 68976.8925000044, - "candidateNs": 69219.97749999719 - }, - { - "baselineNs": 72153.62249999998, - "candidateNs": 70196.04499999332 - }, - { - "baselineNs": 68115.61499999698, - "candidateNs": 68121.47749999895 - }, - { - "baselineNs": 66617.78499999855, - "candidateNs": 70424.47750000065 - }, - { - "baselineNs": 98062.96750000001, - "candidateNs": 103382.06999999784 - }, - { - "baselineNs": 66384.99249999768, - "candidateNs": 67642.16999999917 - }, - { - "baselineNs": 70518.782500003, - "candidateNs": 69587.92250000442 - } - ] - }, - { - "mode": "legacy", - "name": "plural fragment / 100 rows", - "count": 800, - "baselineNs": 26386.908749996113, - "candidateNs": 27629.483750001782, - "ratio": 1.0432064553896991, - "samples": [ - { - "baselineNs": 27532.587499999863, - "candidateNs": 27844.713750000665 - }, - { - "baselineNs": 26901.695000001382, - "candidateNs": 28444.586249997883 - }, - { - "baselineNs": 26669.1687499997, - "candidateNs": 27974.93624999788 - }, - { - "baselineNs": 26221.67250000075, - "candidateNs": 28121.02374999995 - }, - { - "baselineNs": 25979.79000000123, - "candidateNs": 29486.442499996883 - }, - { - "baselineNs": 49468.54625000015, - "candidateNs": 39989.70625000311 - }, - { - "baselineNs": 28890.252500000315, - "candidateNs": 28146.610000003417 - }, - { - "baselineNs": 27164.804999997617, - "candidateNs": 26535.0137500036 - }, - { - "baselineNs": 26588.79124999657, - "candidateNs": 28754.77250000131 - }, - { - "baselineNs": 25490.29000000246, - "candidateNs": 26483.17874999975 - }, - { - "baselineNs": 26794.942500000616, - "candidateNs": 27989.65124999995 - }, - { - "baselineNs": 28065.281250001135, - "candidateNs": 26820.72875000358 - }, - { - "baselineNs": 25929.08124999667, - "candidateNs": 26617.044999998143 - }, - { - "baselineNs": 26386.908749996113, - "candidateNs": 26313.095000000427 - }, - { - "baselineNs": 26017.047499999535, - "candidateNs": 27938.492500002212 - }, - { - "baselineNs": 25761.741249998522, - "candidateNs": 26929.848750000925 - }, - { - "baselineNs": 39596.02499999619, - "candidateNs": 46405.73250000216 - }, - { - "baselineNs": 25936.15750000026, - "candidateNs": 27629.483750001782 - }, - { - "baselineNs": 25706.197500003324, - "candidateNs": 26354.923750000125 - }, - { - "baselineNs": 26008.556249998946, - "candidateNs": 26361.861249997673 - }, - { - "baselineNs": 26437.25375000031, - "candidateNs": 26589.355000000978 - }, - { - "baselineNs": 25926.088750002236, - "candidateNs": 26419.9837499973 - }, - { - "baselineNs": 25817.496250001568, - "candidateNs": 26932.978750000984 - }, - { - "baselineNs": 25116.45750000298, - "candidateNs": 26287.72250000111 - }, - { - "baselineNs": 25342.172499999833, - "candidateNs": 27060.796250002564 - }, - { - "baselineNs": 25833.388749997543, - "candidateNs": 27034.658749998925 - }, - { - "baselineNs": 25495.30000000232, - "candidateNs": 26659.574999998767 - }, - { - "baselineNs": 48789.262499999495, - "candidateNs": 32122.56125000295 - }, - { - "baselineNs": 33407.353750003494, - "candidateNs": 30784.294999998565 - }, - { - "baselineNs": 30350.851250000233, - "candidateNs": 27722.23375000067 - }, - { - "baselineNs": 27022.648749998552, - "candidateNs": 28855.462499996065 - } - ] - }, - { - "mode": "legacy", - "name": "union list / 100 rows", - "count": 400, - "baselineNs": 59399.06499999779, - "candidateNs": 61791.40999999617, - "ratio": 1.0404216066506868, - "samples": [ - { - "baselineNs": 59116.85500000203, - "candidateNs": 62515.92999999957 - }, - { - "baselineNs": 58865.55750000298, - "candidateNs": 60039.55000000132 - }, - { - "baselineNs": 58877.779999993436, - "candidateNs": 59765.457499997865 - }, - { - "baselineNs": 58223.24249999838, - "candidateNs": 59975.4800000028 - }, - { - "baselineNs": 58348.580000001675, - "candidateNs": 77591.0500000009 - }, - { - "baselineNs": 62939.23250000262, - "candidateNs": 100672.39750000225 - }, - { - "baselineNs": 58878.632500000094, - "candidateNs": 61246.307499995964 - }, - { - "baselineNs": 59512.180000001536, - "candidateNs": 61124.87750000582 - }, - { - "baselineNs": 58598.324999993565, - "candidateNs": 60272.814999998445 - }, - { - "baselineNs": 59693.472500002834, - "candidateNs": 61340.6600000053 - }, - { - "baselineNs": 57712.29999999378, - "candidateNs": 68155.26499999578 - }, - { - "baselineNs": 63698.39250000041, - "candidateNs": 77430.3725000027 - }, - { - "baselineNs": 59530.34000000116, - "candidateNs": 61203.17499999146 - }, - { - "baselineNs": 58204.13250000456, - "candidateNs": 59800.90000000018 - }, - { - "baselineNs": 60236.39750000257, - "candidateNs": 100271.3649999987 - }, - { - "baselineNs": 61259.157499998764, - "candidateNs": 79952.18750000276 - }, - { - "baselineNs": 60877.13249999979, - "candidateNs": 61490.24249999456 - }, - { - "baselineNs": 61025.83999999297, - "candidateNs": 63492.60250000043 - }, - { - "baselineNs": 59332.89000000514, - "candidateNs": 60448.175000001356 - }, - { - "baselineNs": 58594.46750000642, - "candidateNs": 61261.80999999633 - }, - { - "baselineNs": 63254.30249999955, - "candidateNs": 60030.710000000916 - }, - { - "baselineNs": 58350.46000000147, - "candidateNs": 64582.337499996356 - }, - { - "baselineNs": 59399.06499999779, - "candidateNs": 63463.27250000286 - }, - { - "baselineNs": 60036.76999999697, - "candidateNs": 68643.98749999964 - }, - { - "baselineNs": 120632.62499999836, - "candidateNs": 90857.19499999868 - }, - { - "baselineNs": 58479.65250000016, - "candidateNs": 61791.40999999617 - }, - { - "baselineNs": 58318.09749999593, - "candidateNs": 60414.25999999774 - }, - { - "baselineNs": 64220.42749999491, - "candidateNs": 59995.04249999518 - }, - { - "baselineNs": 64329.00750000044, - "candidateNs": 73051.11749999924 - }, - { - "baselineNs": 59678.5699999964, - "candidateNs": 62254.18750000244 - }, - { - "baselineNs": 59117.7824999977, - "candidateNs": 62398.48499999425 - } - ] - }, - { - "mode": "legacy", - "name": "custom scalar list", - "count": 3200, - "baselineNs": 12087.76499999999, - "candidateNs": 12403.173437500072, - "ratio": 1.0245624323850053, - "samples": [ - { - "baselineNs": 15492.706562499734, - "candidateNs": 12150.574062499118 - }, - { - "baselineNs": 13419.469374999835, - "candidateNs": 11616.327187500701 - }, - { - "baselineNs": 12044.248437500755, - "candidateNs": 13205.070312499174 - }, - { - "baselineNs": 12595.587187499861, - "candidateNs": 14952.269374999789 - }, - { - "baselineNs": 12087.76499999999, - "candidateNs": 13202.840937500468 - }, - { - "baselineNs": 20496.047187500608, - "candidateNs": 12822.10593750051 - }, - { - "baselineNs": 11896.158749999586, - "candidateNs": 12144.07749999964 - }, - { - "baselineNs": 11386.041874999364, - "candidateNs": 12403.173437500072 - }, - { - "baselineNs": 12217.920312499475, - "candidateNs": 13024.287812500006 - }, - { - "baselineNs": 13157.611875000155, - "candidateNs": 13242.510000000037 - }, - { - "baselineNs": 11962.556249999352, - "candidateNs": 13420.82812499939 - }, - { - "baselineNs": 19287.888750000093, - "candidateNs": 14722.735312500392 - }, - { - "baselineNs": 12009.591875000751, - "candidateNs": 12803.777499999569 - }, - { - "baselineNs": 11567.35000000026, - "candidateNs": 13419.174999999088 - }, - { - "baselineNs": 11653.5003125, - "candidateNs": 12302.345624999587 - }, - { - "baselineNs": 11931.519687499303, - "candidateNs": 13880.450000000337 - }, - { - "baselineNs": 14575.13468749994, - "candidateNs": 12957.555625000625 - }, - { - "baselineNs": 14684.61062499955, - "candidateNs": 16807.021875000602 - }, - { - "baselineNs": 11908.485312500261, - "candidateNs": 11909.662499999738 - }, - { - "baselineNs": 11098.805000000311, - "candidateNs": 11723.952187500116 - }, - { - "baselineNs": 11320.217187500246, - "candidateNs": 12003.843749999989 - }, - { - "baselineNs": 11441.825312499532, - "candidateNs": 11834.674062499744 - }, - { - "baselineNs": 11237.504687500177, - "candidateNs": 10949.175624999725 - }, - { - "baselineNs": 18314.439687500228, - "candidateNs": 10835.604687499654 - }, - { - "baselineNs": 12703.866875000358, - "candidateNs": 11102.915937499349 - }, - { - "baselineNs": 12891.59937500017, - "candidateNs": 12007.09374999974 - }, - { - "baselineNs": 12331.835625000167, - "candidateNs": 11091.691562500047 - }, - { - "baselineNs": 11830.528749999305, - "candidateNs": 12121.115312500024 - }, - { - "baselineNs": 11538.504999999761, - "candidateNs": 11193.559062500071 - }, - { - "baselineNs": 13480.68812499946, - "candidateNs": 14366.099062500552 - }, - { - "baselineNs": 16184.739374999708, - "candidateNs": 14064.907812499996 - } - ] - }, - { - "mode": "legacy", - "name": "opaque JSON list", - "count": 102400, - "baselineNs": 328.04726562496, - "candidateNs": 336.50984375000803, - "ratio": 1.020969780190783, - "samples": [ - { - "baselineNs": 324.735927734352, - "candidateNs": 329.71359375000725 - }, - { - "baselineNs": 336.60650390626046, - "candidateNs": 342.5912499999839 - }, - { - "baselineNs": 314.9987695312362, - "candidateNs": 332.38759765627185 - }, - { - "baselineNs": 557.2195605468622, - "candidateNs": 360.7671093749687 - }, - { - "baselineNs": 324.28155273439785, - "candidateNs": 336.50984375000803 - }, - { - "baselineNs": 327.4914257812611, - "candidateNs": 333.01563476559437 - }, - { - "baselineNs": 322.705722656238, - "candidateNs": 329.52025390628137 - }, - { - "baselineNs": 331.5036035156283, - "candidateNs": 338.72045898437614 - }, - { - "baselineNs": 331.4998730468588, - "candidateNs": 334.5910742187641 - }, - { - "baselineNs": 319.0810937499933, - "candidateNs": 329.1513964843773 - }, - { - "baselineNs": 316.14038085937324, - "candidateNs": 502.15845703124984 - }, - { - "baselineNs": 316.65581054689085, - "candidateNs": 424.113007812501 - }, - { - "baselineNs": 315.3460058593893, - "candidateNs": 335.20375976564765 - }, - { - "baselineNs": 316.6645117187272, - "candidateNs": 334.64655273441224 - }, - { - "baselineNs": 333.38782226564945, - "candidateNs": 333.5953417968796 - }, - { - "baselineNs": 331.32425781246866, - "candidateNs": 331.85974609374114 - }, - { - "baselineNs": 357.2394433593474, - "candidateNs": 346.84871093745073 - }, - { - "baselineNs": 532.831572265664, - "candidateNs": 353.44653320315444 - }, - { - "baselineNs": 366.81848632817093, - "candidateNs": 342.3475292969158 - }, - { - "baselineNs": 327.51842773436124, - "candidateNs": 345.79515624997725 - }, - { - "baselineNs": 327.4145214844282, - "candidateNs": 334.2803320312271 - }, - { - "baselineNs": 340.21694335933717, - "candidateNs": 337.5934277344328 - }, - { - "baselineNs": 322.7479882812645, - "candidateNs": 339.759238281232 - }, - { - "baselineNs": 333.37294921878424, - "candidateNs": 329.0458300781296 - }, - { - "baselineNs": 314.94995117185454, - "candidateNs": 560.8263769531163 - }, - { - "baselineNs": 346.2356347656481, - "candidateNs": 374.40430664062774 - }, - { - "baselineNs": 365.5280664062843, - "candidateNs": 365.74682617185766 - }, - { - "baselineNs": 334.70857421875166, - "candidateNs": 352.81165039059204 - }, - { - "baselineNs": 331.95983398442763, - "candidateNs": 334.8490820312833 - }, - { - "baselineNs": 320.39745117188545, - "candidateNs": 334.23874999996883 - }, - { - "baselineNs": 328.04726562496, - "candidateNs": 332.25609374994747 - } - ] - }, - { - "mode": "legacy", - "name": "recursive inputs", - "count": 400, - "baselineNs": 29874.46249999266, - "candidateNs": 28628.48250000752, - "ratio": 0.9556535676489639, - "samples": [ - { - "baselineNs": 43298.909999994066, - "candidateNs": 30696.49249999202 - }, - { - "baselineNs": 32629.370000013296, - "candidateNs": 36366.13249998845 - }, - { - "baselineNs": 26842.682499991497, - "candidateNs": 28998.78500000341 - }, - { - "baselineNs": 27812.114999996993, - "candidateNs": 29557.06499998996 - }, - { - "baselineNs": 28465.875000001684, - "candidateNs": 27203.51500000106 - }, - { - "baselineNs": 27174.135000004753, - "candidateNs": 27522.97000000908 - }, - { - "baselineNs": 27206.145000000106, - "candidateNs": 26149.01999999347 - }, - { - "baselineNs": 27872.527499985154, - "candidateNs": 26161.2950000017 - }, - { - "baselineNs": 26729.220000015626, - "candidateNs": 26392.83250000517 - }, - { - "baselineNs": 27393.92499999667, - "candidateNs": 25777.04499999527 - }, - { - "baselineNs": 29694.64750000043, - "candidateNs": 27851.940000000464 - }, - { - "baselineNs": 29874.46249999266, - "candidateNs": 27303.95500000668 - }, - { - "baselineNs": 30032.034999985626, - "candidateNs": 28059.807499994346 - }, - { - "baselineNs": 30815.817499988043, - "candidateNs": 27975.624999999123 - }, - { - "baselineNs": 30111.812499999356, - "candidateNs": 27940.45750000805 - }, - { - "baselineNs": 29629.225000007864, - "candidateNs": 29786.872500008027 - }, - { - "baselineNs": 29806.334999993855, - "candidateNs": 29954.214999997934 - }, - { - "baselineNs": 29175.367499992717, - "candidateNs": 27698.824999988574 - }, - { - "baselineNs": 28400.302499994723, - "candidateNs": 47229.31250000329 - }, - { - "baselineNs": 51988.485000001674, - "candidateNs": 51108.422500001325 - }, - { - "baselineNs": 30336.837499999092, - "candidateNs": 28975.01250001369 - }, - { - "baselineNs": 34320.540000007895, - "candidateNs": 28906.2075000038 - }, - { - "baselineNs": 30342.722500008676, - "candidateNs": 27856.272499993793 - }, - { - "baselineNs": 35724.369999988994, - "candidateNs": 31299.582500014367 - }, - { - "baselineNs": 30217.937500001426, - "candidateNs": 30189.80749999173 - }, - { - "baselineNs": 30379.31750001008, - "candidateNs": 29142.9799999969 - }, - { - "baselineNs": 28810.452500001706, - "candidateNs": 34129.22999999864 - }, - { - "baselineNs": 31016.997499991703, - "candidateNs": 30127.31500000882 - }, - { - "baselineNs": 29400.392499992446, - "candidateNs": 27537.872499997316 - }, - { - "baselineNs": 32587.31500000067, - "candidateNs": 28425.44999999518 - }, - { - "baselineNs": 29936.180000004242, - "candidateNs": 28628.48250000752 - } - ] - } - ] -} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/results/size.json b/packages/rescript-relay/benchmarks/rescript-runtime/results/size.json deleted file mode 100644 index 5a15fce6..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/results/size.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "esbuild": "0.25.12", - "node": "v24.16.0", - "results": { - "baselineEsm": { - "minified": 5578, - "gzip": 2238, - "brotli": 2032 - }, - "candidateEsm": { - "minified": 6328, - "gzip": 2638, - "brotli": 2352 - }, - "baselineCjs": { - "minified": 5786, - "gzip": 2330, - "brotli": 2108 - }, - "candidateCjs": { - "minified": 6426, - "gzip": 2689, - "brotli": 2387 - } - } -} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/results/summary.json b/packages/rescript-relay/benchmarks/rescript-runtime/results/summary.json deleted file mode 100644 index e1d6b4d1..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/results/summary.json +++ /dev/null @@ -1,512 +0,0 @@ -[ - { - "fixtureVersion": 3, - "node": "v24.16.0", - "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", - "samples": 31, - "targetSampleMs": 20, - "initialLoad": [ - 20.17, - 20.63, - 18.13 - ], - "finalLoad": [ - 22.07, - 21.04, - 18.36 - ], - "sha256": { - "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", - "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", - "candidate": "efdf597c559c9b77f3d07ec1c3887eb37708d373d4f820250af2436ce39a08ea", - "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" - }, - "results": [ - { - "mode": "prepared", - "name": "small fragment", - "count": 204800, - "baselineNs": 121.7566015624999, - "candidateNs": 104.14479492187489, - "ratio": 0.8349709257422858 - }, - { - "mode": "prepared", - "name": "unchanged object", - "count": 409600, - "baselineNs": 82.96166992187604, - "candidateNs": 66.24224853515659, - "ratio": 0.7671853743271453 - }, - { - "mode": "prepared", - "name": "nullable query", - "count": 204800, - "baselineNs": 171.84698242187488, - "candidateNs": 142.77499511718972, - "ratio": 0.8231401354539566 - }, - { - "mode": "prepared", - "name": "connection / 100 rows", - "count": 800, - "baselineNs": 28019.937499999516, - "candidateNs": 23009.4787500002, - "ratio": 0.7902347823769934 - }, - { - "mode": "prepared", - "name": "plural fragment / 100 rows", - "count": 1600, - "baselineNs": 21462.98687500007, - "candidateNs": 18526.618125000598, - "ratio": 0.8794271797765583 - }, - { - "mode": "prepared", - "name": "union list / 100 rows", - "count": 1600, - "baselineNs": 29198.695625000255, - "candidateNs": 22342.16062499968, - "ratio": 0.7778951643576937 - }, - { - "mode": "prepared", - "name": "custom scalar list", - "count": 1600, - "baselineNs": 14437.52687500023, - "candidateNs": 13762.3318750002, - "ratio": 0.981652431743633 - }, - { - "mode": "prepared", - "name": "opaque JSON list", - "count": 51200, - "baselineNs": 486.72876953123273, - "candidateNs": 552.9230273437591, - "ratio": 1.139742761268076 - }, - { - "mode": "prepared", - "name": "recursive inputs", - "count": 1600, - "baselineNs": 17189.039375000448, - "candidateNs": 15425.186874999781, - "ratio": 0.8949551895398633 - }, - { - "mode": "legacy", - "name": "small fragment", - "count": 102400, - "baselineNs": 273.1039941406266, - "candidateNs": 272.25033203123417, - "ratio": 1.0088202936374087 - }, - { - "mode": "legacy", - "name": "unchanged object", - "count": 204800, - "baselineNs": 119.56970703124625, - "candidateNs": 118.65616210936736, - "ratio": 1.0026406056022323 - }, - { - "mode": "legacy", - "name": "nullable query", - "count": 102400, - "baselineNs": 410.2593359375106, - "candidateNs": 430.05709960937105, - "ratio": 1.0382845115265 - }, - { - "mode": "legacy", - "name": "connection / 100 rows", - "count": 400, - "baselineNs": 62852.29750000326, - "candidateNs": 60790.202500002124, - "ratio": 0.9704859580920145 - }, - { - "mode": "legacy", - "name": "plural fragment / 100 rows", - "count": 800, - "baselineNs": 29465.092499999628, - "candidateNs": 28555.748750000017, - "ratio": 0.9673666667809608 - }, - { - "mode": "legacy", - "name": "union list / 100 rows", - "count": 400, - "baselineNs": 83758.23749999654, - "candidateNs": 82353.2350000005, - "ratio": 1.0079768791213282 - }, - { - "mode": "legacy", - "name": "custom scalar list", - "count": 1600, - "baselineNs": 12798.784999999953, - "candidateNs": 15587.23687499878, - "ratio": 1.0955781158925082 - }, - { - "mode": "legacy", - "name": "opaque JSON list", - "count": 102400, - "baselineNs": 349.20759765618925, - "candidateNs": 354.2060253906243, - "ratio": 1.0446409110718158 - }, - { - "mode": "legacy", - "name": "recursive inputs", - "count": 800, - "baselineNs": 30331.65625000038, - "candidateNs": 31331.545000002734, - "ratio": 1.0406183435481944 - } - ], - "run": 1 - }, - { - "fixtureVersion": 3, - "node": "v24.16.0", - "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", - "samples": 31, - "targetSampleMs": 20, - "initialLoad": [ - 22.07, - 21.04, - 18.36 - ], - "finalLoad": [ - 28.26, - 22.65, - 18.99 - ], - "sha256": { - "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", - "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", - "candidate": "efdf597c559c9b77f3d07ec1c3887eb37708d373d4f820250af2436ce39a08ea", - "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" - }, - "results": [ - { - "mode": "prepared", - "name": "small fragment", - "count": 204800, - "baselineNs": 104.14513671874958, - "candidateNs": 95.33473632812428, - "ratio": 0.9108305326447267 - }, - { - "mode": "prepared", - "name": "unchanged object", - "count": 819200, - "baselineNs": 57.97080200195315, - "candidateNs": 44.429227294921496, - "ratio": 0.7691966977713872 - }, - { - "mode": "prepared", - "name": "nullable query", - "count": 204800, - "baselineNs": 150.56852539062413, - "candidateNs": 120.17709960937319, - "ratio": 0.8092346328869575 - }, - { - "mode": "prepared", - "name": "connection / 100 rows", - "count": 1600, - "baselineNs": 21812.62812499995, - "candidateNs": 17182.614375000183, - "ratio": 0.7829377120803431 - }, - { - "mode": "prepared", - "name": "plural fragment / 100 rows", - "count": 1600, - "baselineNs": 17919.695624999575, - "candidateNs": 13700.545625000586, - "ratio": 0.8055782319164054 - }, - { - "mode": "prepared", - "name": "union list / 100 rows", - "count": 1600, - "baselineNs": 19935.49874999985, - "candidateNs": 15270.431250000911, - "ratio": 0.7984162928963018 - }, - { - "mode": "prepared", - "name": "custom scalar list", - "count": 1600, - "baselineNs": 15037.666250000257, - "candidateNs": 15093.140000000178, - "ratio": 0.9916541786235471 - }, - { - "mode": "prepared", - "name": "opaque JSON list", - "count": 51200, - "baselineNs": 478.9705468749972, - "candidateNs": 591.4377929687475, - "ratio": 1.1668516517895595 - }, - { - "mode": "prepared", - "name": "recursive inputs", - "count": 1600, - "baselineNs": 21305.57562499917, - "candidateNs": 20676.862499999515, - "ratio": 0.9774872831559546 - }, - { - "mode": "legacy", - "name": "small fragment", - "count": 102400, - "baselineNs": 278.36558593747895, - "candidateNs": 265.05880859375, - "ratio": 0.9637947252024088 - }, - { - "mode": "legacy", - "name": "unchanged object", - "count": 204800, - "baselineNs": 133.6500732421797, - "candidateNs": 117.47829589843661, - "ratio": 0.9017787405511776 - }, - { - "mode": "legacy", - "name": "nullable query", - "count": 51200, - "baselineNs": 455.09160156250056, - "candidateNs": 443.55710937502124, - "ratio": 0.9706720376398672 - }, - { - "mode": "legacy", - "name": "connection / 100 rows", - "count": 400, - "baselineNs": 61725.01750000266, - "candidateNs": 60333.2600000067, - "ratio": 0.9813983111234094 - }, - { - "mode": "legacy", - "name": "plural fragment / 100 rows", - "count": 800, - "baselineNs": 28664.328750001005, - "candidateNs": 26220.58375000051, - "ratio": 0.9284585537800738 - }, - { - "mode": "legacy", - "name": "union list / 100 rows", - "count": 400, - "baselineNs": 62901.56499999285, - "candidateNs": 63541.09750000134, - "ratio": 1.0522648822420053 - }, - { - "mode": "legacy", - "name": "custom scalar list", - "count": 3200, - "baselineNs": 11616.421562499681, - "candidateNs": 12326.83624999936, - "ratio": 1.05460484430652 - }, - { - "mode": "legacy", - "name": "opaque JSON list", - "count": 102400, - "baselineNs": 336.435205078125, - "candidateNs": 341.56414062497475, - "ratio": 1.0231712783309246 - }, - { - "mode": "legacy", - "name": "recursive inputs", - "count": 800, - "baselineNs": 28766.95875000223, - "candidateNs": 30134.682500001873, - "ratio": 1.0391593275107527 - } - ], - "run": 2 - }, - { - "fixtureVersion": 3, - "node": "v24.16.0", - "cpu": "AMD RYZEN AI MAX+ 395 w/ Radeon 8060S", - "samples": 31, - "targetSampleMs": 20, - "initialLoad": [ - 20.68, - 21.39, - 18.74 - ], - "finalLoad": [ - 19.18, - 20.96, - 18.69 - ], - "sha256": { - "baseline": "7f68600a1480e8bfa22b754383a9734dcbaaccc55f7fbf923c06489864287294", - "preparedBaseline": "da045e26c642da31d9b9808b840b65852bd58fbf683d1f5b3ba6ad80e60b2847", - "candidate": "efdf597c559c9b77f3d07ec1c3887eb37708d373d4f820250af2436ce39a08ea", - "fixtures": "d660fba22de94a8c016e773830d1c9f1b24fc3ce46bfd2016c5e6d66de57d164" - }, - "results": [ - { - "mode": "prepared", - "name": "small fragment", - "count": 409600, - "baselineNs": 102.4374340820311, - "candidateNs": 91.70031738281237, - "ratio": 0.9006024123311214 - }, - { - "mode": "prepared", - "name": "unchanged object", - "count": 409600, - "baselineNs": 55.89947509765713, - "candidateNs": 44.29194091796873, - "ratio": 0.7933846994786131 - }, - { - "mode": "prepared", - "name": "nullable query", - "count": 204800, - "baselineNs": 148.93603515625298, - "candidateNs": 123.57809570312739, - "ratio": 0.8220193300149227 - }, - { - "mode": "prepared", - "name": "connection / 100 rows", - "count": 1600, - "baselineNs": 21940.737499999726, - "candidateNs": 18028.042500000083, - "ratio": 0.8210054435040013 - }, - { - "mode": "prepared", - "name": "plural fragment / 100 rows", - "count": 1600, - "baselineNs": 15024.559375000308, - "candidateNs": 12962.843749999138, - "ratio": 0.8388993027599011 - }, - { - "mode": "prepared", - "name": "union list / 100 rows", - "count": 1600, - "baselineNs": 18634.26312499996, - "candidateNs": 14601.722500000276, - "ratio": 0.8197016737223956 - }, - { - "mode": "prepared", - "name": "custom scalar list", - "count": 3200, - "baselineNs": 11663.735624999845, - "candidateNs": 11913.714062499706, - "ratio": 1.02246230509656 - }, - { - "mode": "prepared", - "name": "opaque JSON list", - "count": 51200, - "baselineNs": 441.32806640622135, - "candidateNs": 538.5150781249947, - "ratio": 1.2004831145919181 - }, - { - "mode": "prepared", - "name": "recursive inputs", - "count": 1600, - "baselineNs": 16857.66187499894, - "candidateNs": 14194.308749999891, - "ratio": 0.8569818680573524 - }, - { - "mode": "legacy", - "name": "small fragment", - "count": 102400, - "baselineNs": 263.53763671874475, - "candidateNs": 255.13298828126807, - "ratio": 0.9817418609062459 - }, - { - "mode": "legacy", - "name": "unchanged object", - "count": 102400, - "baselineNs": 111.38375976564419, - "candidateNs": 110.24087890621814, - "ratio": 0.9926745976948665 - }, - { - "mode": "legacy", - "name": "nullable query", - "count": 102400, - "baselineNs": 446.55356445311156, - "candidateNs": 429.20505859374464, - "ratio": 0.9638199985851299 - }, - { - "mode": "legacy", - "name": "connection / 100 rows", - "count": 400, - "baselineNs": 64871.20750000031, - "candidateNs": 65180.14249999396, - "ratio": 1.0035241512219875 - }, - { - "mode": "legacy", - "name": "plural fragment / 100 rows", - "count": 800, - "baselineNs": 26386.908749996113, - "candidateNs": 27629.483750001782, - "ratio": 1.0432064553896991 - }, - { - "mode": "legacy", - "name": "union list / 100 rows", - "count": 400, - "baselineNs": 59399.06499999779, - "candidateNs": 61791.40999999617, - "ratio": 1.0404216066506868 - }, - { - "mode": "legacy", - "name": "custom scalar list", - "count": 3200, - "baselineNs": 12087.76499999999, - "candidateNs": 12403.173437500072, - "ratio": 1.0245624323850053 - }, - { - "mode": "legacy", - "name": "opaque JSON list", - "count": 102400, - "baselineNs": 328.04726562496, - "candidateNs": 336.50984375000803, - "ratio": 1.020969780190783 - }, - { - "mode": "legacy", - "name": "recursive inputs", - "count": 400, - "baselineNs": 29874.46249999266, - "candidateNs": 28628.48250000752, - "ratio": 0.9556535676489639 - } - ], - "run": 3 - } -] diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/size.js b/packages/rescript-relay/benchmarks/rescript-runtime/size.js deleted file mode 100644 index 2f5dff1e..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/size.js +++ /dev/null @@ -1,23 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const zlib = require("zlib"); -const esbuild = require("esbuild"); -const {buildConversionModules} = require("../../scripts/build-conversion-modules"); -async function measure() { - const output = path.join(__dirname, "output"); - buildConversionModules(path.join(output, "baseline")); - const results = {}; - for (const [name, entry] of [ - ["baselineEsm", path.join(output, "baseline/utils.mjs")], - ["candidateEsm", path.join(output, "utils.mjs")], - ["baselineCjs", path.resolve(__dirname, "../../src/utils.js")], - ["candidateCjs", path.join(output, "utils.cjs")], - ]) { - const result = await esbuild.build({entryPoints: [entry], bundle: true, minify: true, format: "esm", write: false}); - const bytes = result.outputFiles[0].contents; - results[name] = {minified: bytes.length, gzip: zlib.gzipSync(bytes, {level: 9}).length, brotli: zlib.brotliCompressSync(bytes).length}; - } - fs.writeFileSync(path.join(output, "size.json"), JSON.stringify({esbuild: esbuild.version, node: process.version, results}, null, 2) + "\n"); - console.table(results); -} -measure().catch(error => {console.error(error); process.exitCode = 1;}); diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res deleted file mode 100644 index 30a32bf9..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_Conversion.res +++ /dev/null @@ -1,312 +0,0 @@ -open RescriptRelay_ConversionInterop - -type rec node = {children: dict, instructions: dict} - -%%private( - let isOption = value => (get(value, "BS_PRIVATE_NESTED_SOME_NONE"): float) >= 0.0 - let isMetadata = key => - key->startsWith("__") && - key !== "__typename" && - key !== "__id" && - !(key->startsWith("__relay_internal")) - let makeNode = () => {children: create(), instructions: create()} - let readPlan = plan => { - let rawRoots: value = if truthy(plan) { - get(plan, "roots") - } else { - jsUndefined - } - if ( - !truthy(plan) || - get(plan, "version") !== cast(2) || - !truthy(rawRoots) || - typeOf(rawRoots) !== "object" - ) { - fail("Invalid conversion plan: expected version 2 and roots") - } - let roots = create() - let rootNames = keys(rawRoots) - for rootIndex in 0 to Array.length(rootNames) - 1 { - let name = unsafeAt(rootNames, rootIndex) - let entries: value = get(rawRoots, name) - if !isArray(entries) { - fail("Invalid conversion root: " ++ name) - } - let root = makeNode() - set(roots, name, root) - for i in 0 to length(entries) - 1 { - let entry = at(entries, i) - let path: value = if truthy(entry) { - get(entry, "path") - } else { - jsUndefined - } - if !isArray(path) { - fail("Invalid conversion path in " ++ name) - } - let target = ref(root) - for j in 0 to length(path) - 1 { - let rawKey = at(path, j) - if typeOf(rawKey) !== "string" { - fail("Invalid conversion path in " ++ name) - } - let key: string = cast(rawKey) - if hasOwn(target.contents.children, key) { - target := get(target.contents.children, key) - } else { - let child = makeNode() - set(target.contents.children, key, child) - target := child - } - } - let instructionKeys = keys(entry) - for keyIndex in 0 to Array.length(instructionKeys) - 1 { - let key = unsafeAt(instructionKeys, keyIndex) - switch key { - | "path" => () - | "list" | "scalar" | "union" | "reference" | "opaque" | "fragments" => - let value: value = get(entry, key) - if ( - hasOwn(target.contents.instructions, key) && - get(target.contents.instructions, key) !== value - ) { - fail("Conflicting conversion instruction: " ++ key) - } - set(target.contents.instructions, key, value) - | _ => fail("Unknown conversion instruction: " ++ key) - } - } - } - } - roots - } -) - -let prepareConversion = ( - plan: value, - callbacks: value, - nullable: value, - rawRootName: value, -): converter => { - if nullable !== jsUndefined && nullable !== jsNull { - fail("Invalid conversion nullable sentinel") - } - let rootName: string = if rawRootName === jsUndefined { - "__root" - } else { - cast(rawRootName) - } - let roots = readPlan(plan) - if !hasOwn(roots, rootName) { - fail("Missing conversion root: " ++ rootName) - } - let converters: dict = create() - let arrayOf = (convert: converter): converter => - values => { - let result = ref(jsUndefined) - for i in 0 to length(values) - 1 { - if hasIndex(i, values) { - let value = at(values, i) - let next = convert(value) - if next !== value { - if result.contents === jsUndefined { - result := slice(values) - } - put(result.contents, i, next) - } - } - } - if result.contents === jsUndefined { - values - } else { - result.contents - } - } - let nullableOnly: converter = value => - if isNullable(value) { - nullable - } else { - value - } - let optional = (convert: converter) => { - if convert === nullableOnly { - nullableOnly - } else { - value => - if isNullable(value) { - nullable - } else if isOption(value) { - value - } else { - convert(value) - } - } - } - let rec any: converter = value => { - if isNullable(value) { - nullable - } else if typeOf(value) !== "object" || isOption(value) { - value - } else if isArray(value) { - anyArray(value) - } else { - plainRecord(value, any, isMetadata) - } - } - and anyArray: converter = values => { - let result = ref(jsUndefined) - for i in 0 to length(values) - 1 { - if hasIndex(i, values) { - let value = at(values, i) - let next = any(value) - if next !== value { - if result.contents === jsUndefined { - result := slice(values) - } - put(result.contents, i, next) - } - } - } - if result.contents === jsUndefined { - values - } else { - result.contents - } - } - let callback = name => { - if ( - !truthy(callbacks) || !hasOwn(callbacks, name) || typeOf(get(callbacks, name)) !== "function" - ) { - fail("Missing conversion callback: " ++ name) - } - (get(callbacks, name): converter) - } - let rec compile = node => { - let ops = node.instructions - let operations = ["scalar", "union", "reference"]->Array.filter(key => hasOwn(ops, key)) - let allOperations = if hasOwn(ops, "opaque") { - Array.concat(operations, ["opaque"]) - } else { - operations - } - if Array.length(allOperations) > 1 { - fail("Conflicting conversion operations: " ++ Array.join(allOperations, ", ")) - } - for operationIndex in 0 to Array.length(operations) - 1 { - let key = unsafeAt(operations, operationIndex) - if typeOf(get(ops, key)) !== "string" { - fail("Invalid conversion " ++ key) - } - } - let flags = ["opaque", "fragments"] - for flagIndex in 0 to Array.length(flags) - 1 { - let key = unsafeAt(flags, flagIndex) - if hasOwn(ops, key) && get(ops, key) !== cast(true) { - fail("Invalid conversion " ++ key) - } - } - let rawDepth: value = get(ops, "list") - let depth: int = if rawDepth === jsUndefined { - 0 - } else { - cast(rawDepth) - } - if !isSafeInteger(cast(depth)) || depth < 0 { - fail("Invalid conversion list depth") - } - let names = keys(node.children) - let scalar: value = get(ops, "scalar") - let reference: value = get(ops, "reference") - let opaque = get(ops, "opaque") === cast(true) - let fragments = get(ops, "fragments") === cast(true) - let base = if scalar !== jsUndefined || opaque || reference !== jsUndefined { - if Array.length(names) > 0 || fragments { - fail("Leaf conversion cannot have child fields or fragments") - } - if scalar !== jsUndefined { - callback(cast(scalar)) - } else if opaque { - nullableOnly - } else { - let target: string = cast(reference) - if !hasOwn(roots, target) { - fail("Missing conversion reference: " ++ target) - } - value => - (get(converters, target): converter)( - if hasOwn(value, "__$inputUnion") { - unwrapInputUnion(value) - } else { - value - }, - ) - } - } else { - let children: dict = create() - for childIndex in 0 to Array.length(names) - 1 { - let name = unsafeAt(names, childIndex) - set(children, name, compile(get(node.children, name))) - } - let union: value = get(ops, "union") - if union !== jsUndefined { - if fragments { - fail("Union fragments belong on member plans") - } - let union = callback(cast(union)) - let member = value => { - let convert: converter = get(children, get(value, "__typename")) - if cast(convert) === jsUndefined { - any - } else { - convert - } - } - if nullable === jsNull { - value => member(value)(union(value)) - } else { - value => union(member(value)(value)) - } - } else if Array.length(names) === 0 && !fragments { - any - } else { - makeRecord(children, fragments, any, isMetadata) - } - } - let convert = ref(optional(base)) - for _i in 1 to depth { - convert := optional(arrayOf(convert.contents)) - } - convert.contents - } - let rootNames = keys(roots) - for rootIndex in 0 to Array.length(rootNames) - 1 { - let name = unsafeAt(rootNames, rootIndex) - set(converters, name, compile(get(roots, name))) - } - let convert: converter = get(converters, rootName) - let plural = arrayOf(convert) - let root: node = get(roots, rootName) - let allowPlural = - get(root.instructions, "list") === jsUndefined && - get(root.instructions, "scalar") === jsUndefined && - get(root.instructions, "reference") === jsUndefined && - get(root.instructions, "opaque") !== cast(true) - value => - if isArray(value) && allowPlural { - plural(value) - } else { - convert(value) - } -} - -%%private( - let emptyPlan: value = %raw(json`{"version":2,"roots":{"__root":[]}}`) - let readWithoutPlan = prepareConversion(emptyPlan, jsUndefined, jsUndefined, jsUndefined) - let writeWithoutPlan = prepareConversion(emptyPlan, jsUndefined, jsNull, jsUndefined) -) -let convertWithoutPlan = (value, nullable) => - if nullable === jsNull { - writeWithoutPlan(value) - } else { - readWithoutPlan(value) - } diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res deleted file mode 100644 index cb719a33..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_ConversionInterop.res +++ /dev/null @@ -1,109 +0,0 @@ -// Dynamic Relay values include null, undefined, custom scalar instances and -// ReScript option markers. Keep unchecked property access at this FFI boundary. -type value -type converter = value => value -external jsUndefined: value = "%undefined" -external jsNull: value = "%null" -external cast: 'a => 'b = "%identity" -external isNullable: value => bool = "%is_nullable" -external typeOf: 'a => string = "%typeof" -@get_index external get: ('object, string) => 'value = "" -@set_index external set: ('object, string, 'value) => unit = "" -@get_index external unsafeAt: (array<'a>, int) => 'a = "" -@get_index external at: (value, int) => value = "" -@set_index external put: (value, int, value) => unit = "" -@get external length: 'a => int = "length" -@send external slice: value => value = "slice" -@send external startsWith: (string, string) => bool = "startsWith" -@val external isArray: 'a => bool = "Array.isArray" -@val external keys: 'a => array = "Object.keys" -@val external create: (@as(json`null`) _, unit) => dict<'a> = "Object.create" -@val external isSafeInteger: value => bool = "Number.isSafeInteger" -@val external truthy: 'a => bool = "Boolean" -let hasOwn: ( - 'object, - string, -) => bool = %raw(`(object, key) => Object.prototype.hasOwnProperty.call(object, key)`) -let hasIndex: (int, value) => bool = %raw(`(index, value) => index in value`) -let unwrapInputUnion: value => value = %raw(`value => ({[value.__$inputUnion]: value._0})`) -let fail: string => 'a = %raw(`message => {throw new Error(message);}`) -// ReScript has no allocation-free `for ... in` construct. These two kernels -// preserve own-key order and lazy copying without allocating a keys array. -let plainRecord: ( - value, - converter, - string => bool, -) => value = %raw(`(value, convert, isMetadata) => { - let result; - for (const key in value) { - if (!Object.prototype.hasOwnProperty.call(value,key) || isMetadata(key)) continue; - const original = value[key]; - const next = convert(original); - if (next !== original) { - if (result === undefined) result = {...value}; - result[key] = next; - } - } - return result === undefined ? value : result; -}`) -let makeRecord: ( - dict, - bool, - converter, - string => bool, -) => converter = %raw(`(fields, fragments, any, isMetadata) => value => { - let result; - if (fragments) { - const refs = {...value}; - result = {...value, fragmentRefs: refs, updatableFragmentRefs: refs}; - } - for (const key in value) { - if (!Object.prototype.hasOwnProperty.call(value,key) || isMetadata(key)) continue; - const original = value[key]; - const convert = fields[key]; - const next = convert === undefined ? any(original) : convert(original); - if (next !== original) { - if (result === undefined) result = {...value}; - result[key] = next; - } - } - return result === undefined ? value : result; -}`) -let withLegacyFragments: value => value = %raw(`value => {const result = Object.assign({},value); result.fragmentRefs = Object.assign({},value); result.updatableFragmentRefs = result.fragmentRefs; return result;}`) -let hasProperty: (string, value) => bool = %raw(`(key, value) => key in value`) -@send external map: (value, (value, int, value) => value) => value = "map" -let legacyRecord: ( - value, - string, - value, - value, - value, - value, - bool, - (value, value, value, string, value, value, value) => value, -) => value = %raw(`(maps, prefix, obj, instructions, converters, nullable, fragment, convertField) => { - let result; - if (fragment) { - result = Object.assign({},obj); - result.fragmentRefs = Object.assign({},obj); - result.updatableFragmentRefs = result.fragmentRefs; - } - for (const key in obj) { - if (key.startsWith('__') && key !== '__typename' && key !== '__id' && !key.startsWith('__relay_internal')) continue; - const value = obj[key]; - let converted; - if (value == null) converted = nullable; - else if (value.BS_PRIVATE_NESTED_SOME_NONE >= 0) continue; - else { - const path = prefix + key; - let instruction = instructions[path]; - if (instruction === undefined && typeof value !== 'object') continue; - converted = convertField(value, instruction, maps, path, instructions, converters, nullable); - } - if (converted !== value) { - if (result === undefined) result = Object.assign({},obj); - result[key] = converted; - } - } - return result === undefined ? obj : result; -}`) diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_LegacyConversion.res b/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_LegacyConversion.res deleted file mode 100644 index 93deffe1..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/src/RescriptRelay_LegacyConversion.res +++ /dev/null @@ -1,261 +0,0 @@ -open RescriptRelay_ConversionInterop - -%%private( - let empty: value = %raw(`Object.freeze({})`) - let fallback = value => - if truthy(value) { - value - } else { - empty - } - let unwrap = value => - if !isNullable(value) && typeOf(value) === "object" && hasProperty("__$inputUnion", value) { - unwrapInputUnion(value) - } else { - value - } -) - -let rec traverser = ( - root: value, - instructionMaps: value, - callbacks: value, - nullable: value, - rootObjectKey: value, -): value => { - if !truthy(root) { - nullable - } else { - let maps = if truthy(instructionMaps) { - instructionMaps - } else { - empty - } - let key: string = if truthy(rootObjectKey) { - cast(rootObjectKey) - } else { - "__root" - } - let instructions = fallback(get(maps, key)) - let callbacks = if truthy(callbacks) { - callbacks - } else { - empty - } - let rootInstruction = fallback(get(instructions, "")) - let union: value = get(callbacks, get(rootInstruction, "u")) - let fragment = get(rootInstruction, "f") === cast("") - let convertRoot = value => { - if isNullable(value) { - nullable - } else { - let prefix = if !isNullable(union) { - (get(value, "__typename"): string) ++ "_" - } else { - "" - } - let hasFragment = if !isNullable(union) { - get(fallback(get(instructions, get(value, "__typename"))), "f") === cast("") - } else { - fragment - } - let result = legacyRecord( - maps, - prefix, - value, - instructions, - callbacks, - nullable, - hasFragment, - convertField, - ) - if !isNullable(union) { - (cast(union): converter)(result) - } else { - result - } - } - } - if isArray(root) { - let result = ref(jsUndefined) - let i = ref(0) - while i.contents < length(root) { - let index = i.contents - if hasIndex(index, root) { - let original = at(root, index) - let next = convertRoot(original) - if next !== original { - if result.contents === jsUndefined { - result := slice(root) - } - put(result.contents, index, next) - } - } - i := i.contents + 1 - } - if result.contents === jsUndefined { - root - } else { - result.contents - } - } else { - convertRoot(root) - } - } -} -and convertUnion = (value, convert: converter, maps, path, instructions, callbacks, nullable) => { - let unionPath = path ++ "_" ++ (get(value, "__typename"): string) - let fragment = get(fallback(get(instructions, unionPath)), "f") === cast("") - let raw = if nullable === jsNull { - convert(value) - } else { - value - } - let result = legacyRecord( - maps, - unionPath ++ "_", - raw, - instructions, - callbacks, - nullable, - fragment, - convertField, - ) - if nullable === jsUndefined { - convert(result) - } else { - result - } -} -and convertField = (value, rawInstruction, maps, path, instructions, callbacks, nullable) => { - let instruction = if truthy(rawInstruction) { - rawInstruction - } else { - empty - } - let array = isArray(value) - let customArray = if typeOf(get(instruction, "ca")) === "string" { - get(callbacks, get(instruction, "ca")) - } else { - jsUndefined - } - if array && truthy(customArray) { - map(value, (item, index, array) => { - if isNullable(item) { - nullable - } else if (get(item, "BS_PRIVATE_NESTED_SOME_NONE"): float) >= 0.0 { - item - } else { - (cast(customArray): (value, int, value) => value)(item, index, array) - } - }) - } else { - let blocked = typeOf(get(instruction, "b")) === "string" - if blocked && get(instruction, "b") !== cast("a") { - value - } else { - let custom = if typeOf(get(instruction, "c")) === "string" { - get(callbacks, get(instruction, "c")) - } else { - jsUndefined - } - if array && truthy(custom) { - (cast(custom): converter)(value) - } else { - let root = if typeOf(get(instruction, "r")) === "string" { - get(maps, get(instruction, "r")) - } else { - jsUndefined - } - let enumConverter = if typeOf(get(instruction, "e")) === "string" { - get(callbacks, get(instruction, "e")) - } else { - jsUndefined - } - let union = if typeOf(get(instruction, "u")) === "string" { - get(callbacks, get(instruction, "u")) - } else { - jsUndefined - } - let fragment = get(instruction, "f") === cast("") - if array { - let result = ref(jsUndefined) - let i = ref(0) - while i.contents < length(value) { - let index = i.contents - if hasIndex(index, value) { - let item = at(value, index) - let next = if isNullable(item) { - nullable - } else if truthy(root) { - traverser(unwrap(item), maps, callbacks, nullable, get(instruction, "r")) - } else if truthy(enumConverter) { - (cast(enumConverter): converter)(item) - } else if ( - truthy(union) && typeOf(item) === "object" && !isNullable(get(item, "__typename")) - ) { - convertUnion(item, cast(union), maps, path, instructions, callbacks, nullable) - } else if typeOf(item) === "object" && !isArray(item) { - if blocked { - if fragment { - withLegacyFragments(item) - } else { - item - } - } else { - legacyRecord( - maps, - path ++ "_", - item, - instructions, - callbacks, - nullable, - fragment, - convertField, - ) - } - } else { - item - } - if next !== item { - if result.contents === jsUndefined { - result := slice(value) - } - put(result.contents, index, next) - } - } - i := i.contents + 1 - } - if result.contents === jsUndefined { - value - } else { - result.contents - } - } else if truthy(root) { - traverser(unwrap(value), maps, callbacks, nullable, get(instruction, "r")) - } else if truthy(custom) { - (cast(custom): converter)(value) - } else if truthy(enumConverter) { - (cast(enumConverter): converter)(value) - } else if typeOf(value) === "object" { - if truthy(union) && !isNullable(get(value, "__typename")) { - convertUnion(value, cast(union), maps, path, instructions, callbacks, nullable) - } else { - legacyRecord( - maps, - path ++ "_", - value, - instructions, - callbacks, - nullable, - fragment, - convertField, - ) - } - } else { - value - } - } - } - } -} diff --git a/packages/rescript-relay/benchmarks/rescript-runtime/test.js b/packages/rescript-relay/benchmarks/rescript-runtime/test.js deleted file mode 100644 index 4d0e3cc8..00000000 --- a/packages/rescript-relay/benchmarks/rescript-runtime/test.js +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env node -const assert = require("assert/strict"); -const path = require("path"); -const {pathToFileURL} = require("url"); -const {spawn} = require("child_process"); -async function test() { - const candidate = require("./output/utils.cjs"); - const esm = await import(pathToFileURL(path.join(__dirname, "output/utils.mjs"))); - assert.deepEqual(Object.keys(candidate).sort(), Object.keys(esm).sort()); - const {cases, converters} = require("../fixtures"); - for (const fixture of cases) { - for (const nullable of [null, undefined]) { - const convert = runtime => runtime.runConversion(runtime.prepareConversion(fixture.plan, converters, nullable), fixture.root); - assert.deepEqual(convert(esm), convert(candidate), fixture.name); - assert.deepEqual(esm.traverser(fixture.root, fixture.maps, converters, nullable), candidate.traverser(fixture.root, fixture.maps, converters, nullable), fixture.name); - assert.deepEqual(esm.convertWithoutPlan(fixture.root, nullable), candidate.convertWithoutPlan(fixture.root, nullable), fixture.name); - } - } - const config = { - ...require("../../jest.config"), - rootDir: path.resolve(__dirname, "../.."), - bail: false, - resolver: path.join(__dirname, "resolver.js"), - }; - await new Promise((resolve, reject) => { - const child = spawn(process.execPath, [require.resolve("jest/bin/jest"), "--config", JSON.stringify(config), "--runInBand"], {stdio: "inherit"}); - child.on("error", reject); - child.on("exit", code => code === 0 ? resolve() : reject(new Error(`Jest exited ${code}`))); - }); -} -test().catch(error => {console.error(error); process.exitCode = 1;}); From de842ba8c1c574e6bb4594dda753f1f589fdf35c Mon Sep 17 00:00:00 2001 From: Gabriel Nordeborn Date: Wed, 23 Sep 2026 11:19:01 +0200 Subject: [PATCH 23/23] Remove redundant release coordination note from changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dba48e48..e03599e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # master -- Speed up response and variable conversion with prepared conversion plans and smaller generated instructions. Fix custom-scalar, nested-list, union, and plural `@catch` conversion edge cases; expand regression coverage and add performance/bundle-size benchmarks. Compiler and runtime updates must ship together. +- Speed up response and variable conversion with prepared conversion plans and smaller generated instructions. Fix custom-scalar, nested-list, union, and plural `@catch` conversion edge cases; expand regression coverage and add performance/bundle-size benchmarks. - fix remove-unused-fields command. https://github.com/zth/rescript-relay/pull/636