Skip to content

Commit

Permalink
Merge pull request #158 from usegraffy/aravind/pg-val-null
Browse files Browse the repository at this point in the history
pg: Fix { $val: null } without $put: true
  • Loading branch information
aravindet authored May 7, 2024
2 parents 06663d1 + c7b01db commit 7e2c56a
Show file tree
Hide file tree
Showing 32 changed files with 2,079 additions and 1,816 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [14.x]
node-version: [20.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
3 changes: 2 additions & 1 deletion biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
"noForEach": "off"
},
"a11y": {
"all": false
"all": false,
"useButtonType": { "level": "off" }
},
"style": {
"noParameterAssign": "off"
Expand Down
2 changes: 1 addition & 1 deletion jest.config.cjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const path = require('path');
const path = require('node:path');

module.exports = {
verbose: true,
Expand Down
30 changes: 14 additions & 16 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@
"pg:clean": "docker rm -f graffypg",
"pg:psql": "docker run --name pgrepl -e POSTGRES_PASSWORD=graffy -d postgres:alpine && until docker exec -it pgrepl psql -U postgres; do sleep 0.5; done ; docker rm -f pgrepl"
},
"workspaces": [
"src/*"
],
"workspaces": ["src/*"],
"author": "aravindet",
"license": "Apache-2.0",
"bugs": {
Expand All @@ -29,37 +27,37 @@
"devDependencies": {
"@babel/preset-react": "^7.16.7",
"@biomejs/biome": "^1.5.3",
"@faker-js/faker": "^7.6.0",
"@testing-library/react": "^13.4.0",
"@faker-js/faker": "^8.4.1",
"@testing-library/react": "^15.0.0",
"@types/debug": "^4.1.7",
"@types/jest": "^29.2.4",
"@types/jest": "^29.5.12",
"@types/pg": "^8.6.5",
"@types/react": "^18.0.26",
"@vitejs/plugin-react": "^3.0.0",
"@vitejs/plugin-react": "^4.2.1",
"debug": "^4.3.3",
"express": "^4.18.2",
"jest": "^29.3.1",
"jest-environment-jsdom": "^29.3.1",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"lodash": "^4.17.19",
"merge-async-iterators": "^0.2.1",
"nanoid": "^4.0.0",
"p-map": "^5.3.0",
"nanoid": "^5.0.7",
"p-map": "^7.0.2",
"pg": "^8.7.1",
"prop-types": "^15.8.1",
"puppeteer": "^19.4.0",
"puppeteer": "^22.6.3",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-test-renderer": "^18.2.0",
"rimraf": "^3.0.2",
"rimraf": "^5.0.5",
"sql-template-tag": "^5.0.3",
"typescript": "^4.9.4",
"typescript": "^5.4.5",
"uuid": "^9.0.0",
"vite": "^4.0.5",
"vite": "^5.2.8",
"ws": "^8.11.0",
"yargs": "^17.6.2"
},
"peerDependencies": {
"pg": "^8.0.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
}
}
}
9 changes: 5 additions & 4 deletions scripts/build.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { builtinModules } from 'module';
import { mkdir, readFile, writeFile } from 'fs/promises';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { builtinModules } from 'node:module';
import { build as viteBuild } from 'vite';
import { depVersions, peerDepVersions, use } from './deps.js';
import { dst, ownPattern, read, src } from './utils.js';

const depPattern = /^[^@][^/]*|^@[^/]*\/[^/]*/;

// ESM-only deps are built into the bundle rather than
// keeping them external, to prevent
// keeping them external, to prevent installation errors
// in commonJS projects.
const esmOnlyDeps = ['sql-template-tag', 'nanoid'];

export default async function build(name, version, watch, onUpdate) {
Expand Down Expand Up @@ -113,7 +114,7 @@ export default async function build(name, version, watch, onUpdate) {
dependencies[dep] = version;
} else if (depVersions[dep]) {
dependencies[dep] = depVersions[dep];
} else if (builtinModules.includes(dep)) {
} else if (builtinModules.includes(dep) || dep.startsWith('node:')) {
console.log(`INFO [${name}] ignoring built-in ${dep}`);
} else {
console.warn(`WARN [${name}] unversioned package ${dep}`);
Expand Down
2 changes: 1 addition & 1 deletion scripts/jest.setup.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import util from 'util';
import util from 'node:util';

process.on('unhandledRejection', (reason) => {
console.error('Unhandled Promise Rejection:', reason);
Expand Down
8 changes: 3 additions & 5 deletions scripts/package.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#!/usr/bin/env node

import os from 'os';
import { mkdir, readdir } from 'fs/promises';
import { mkdir, readdir } from 'node:fs/promises';
import os from 'node:os';
import pMap from 'p-map';
import mRimraf from 'rimraf';
import { rimrafSync as rimraf } from 'rimraf';
import yargs from 'yargs';

import build from './build.js';
Expand All @@ -15,8 +15,6 @@ import types, { terminateWorkers } from './types.js';
import { dst, src } from './utils.js';
import version from './version.js';

const { sync: rimraf } = mRimraf;

const argv = yargs(process.argv.slice(2))
.usage('$0 <version> [--publish] [--link] [--watch] [--notypes]')
.boolean('publish')
Expand Down
4 changes: 2 additions & 2 deletions scripts/tscworker.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { dirname } from 'path';
import { dirname } from 'node:path';
import { parentPort } from 'node:worker_threads';
import ts from 'typescript';
import { parentPort } from 'worker_threads';
import { dst, src } from './utils.js';

parentPort.on('message', (message) => {
Expand Down
2 changes: 1 addition & 1 deletion scripts/types.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Worker } from 'worker_threads';
import { Worker } from 'node:worker_threads';
import { root } from './utils.js';

const workerPool = [];
Expand Down
10 changes: 5 additions & 5 deletions scripts/utils.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { execFile as cExecFile } from 'child_process';
import { readFileSync } from 'fs';
import { join } from 'path';
import { fileURLToPath } from 'url';
import { promisify } from 'util';
import { execFile as cExecFile } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { promisify } from 'node:util';

const execFile = promisify(cExecFile);

Expand Down
2 changes: 1 addition & 1 deletion scripts/version.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default async function version(str) {
.reduce((latest, vstring) => {
const version = vstring
.split(/[.-]/)
.map((seg, i) => (i === 3 ? seg : parseInt(seg)));
.map((seg, i) => (i === 3 ? seg : Number.parseInt(seg)));

for (let i = 0; i < 5; i++) {
const atPre = i === 3;
Expand Down
6 changes: 4 additions & 2 deletions src/common/coding/decodeTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ function decode(nodes = [], { isGraph } = {}) {
(allNums &&
putRanges.length === 1 &&
cmp(putRanges[0].key, 0) === 0 &&
cmp(putRanges[0].end, +Infinity) === 0)
cmp(putRanges[0].end, Number.POSITIVE_INFINITY) === 0)
) {
result = result.reduce(
(collection, item) => {
Expand All @@ -89,7 +89,9 @@ function decode(nodes = [], { isGraph } = {}) {
delete item.$key;
delete item.$val;

if (typeof $val === 'object') {
if ($val === null) {
$val = { $val };
} else if (typeof $val === 'object') {
$val = clone($val);
Object.defineProperty($val, '$val', { value: true });
}
Expand Down
14 changes: 12 additions & 2 deletions src/common/coding/decorate.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export default function decorate(rootGraph, rootQuery) {
: { ...plumGraph };
graph.$val = true;
} else if (Array.isArray(plumGraph)) {
graph = decodeGraph(plumGraph);
graph = deValNull(decodeGraph(plumGraph));
} else {
throw Error('decorate.unexpected_graph');
}
Expand Down Expand Up @@ -152,7 +152,7 @@ export default function decorate(rootGraph, rootQuery) {
children = descend(children, MIN_KEY);
}

const { key, end, limit = Infinity } = encodeArgs(range);
const { key, end, limit = Number.POSITIVE_INFINITY } = encodeArgs(range);
const ix = findFirst(children, key);
let i = ix;
let result;
Expand Down Expand Up @@ -180,6 +180,16 @@ export default function decorate(rootGraph, rootQuery) {
return result;
}

// Replace $val: null produced by
function deValNull(graph) {
if (typeof graph !== 'object' || !graph) return graph;
if ('$val' in graph && graph.$val !== true) return graph.$val;

// Important: update graph in-place to avoid losing non-enumerable props.
for (const prop in graph) graph[prop] = deValNull(graph[prop]);
return graph;
}

function addPageMeta(graph, args) {
if (args.$all) {
Object.assign(graph, { $page: args, $prev: null, $next: null });
Expand Down
2 changes: 1 addition & 1 deletion src/common/coding/encodeTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ function encode(value, { version, isGraph } = {}) {
!isDef($val) &&
!object.some((it) => isDef(it?.$key))
) {
putRange = [encodeArgs({ $since: 0, $until: +Infinity })];
putRange = [encodeArgs({ $since: 0, $until: Number.POSITIVE_INFINITY })];
}

function classifyPut(put) {
Expand Down
23 changes: 23 additions & 0 deletions src/common/coding/test/decorate.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,26 @@ test('alias', () => {
expect(result).toEqual({ bar: expectedArray });
expect(result.bar.$ref).toEqual(expectedArray.$ref);
});

describe('val_null', () => {
test('implicit', () => {
const result = decorate(
[
{
key: e.foo,
version: 0,
children: [{ key: e.bar, version: 0, value: null }],
},
],
{ foo: 1 },
);
expect(result).toEqual({ foo: { bar: null } });
});

test('explicit', () => {
const result = decorate([{ key: e.foo, version: 0, value: null }], {
foo: 1,
});
expect(result).toEqual({ foo: null });
});
});
4 changes: 2 additions & 2 deletions src/common/coding/test/number.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ describe('dencorder', () => {
});

test('infinity', () => {
const v = -Infinity;
const v = Number.NEGATIVE_INFINITY;
expect(v).toEqual(decode(encode(v)));
});

test('nan', () => {
const v = NaN;
const v = Number.NaN;
expect(Number.isNaN(decode(encode(v)))).toBe(true);
});
});
43 changes: 43 additions & 0 deletions src/common/coding/test/roundTrip.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,49 @@ describe('graph', () => {
);
});

test('val_null', () => {
roundTrip({ foo: { $val: null } });
});

test('val_scalar', () => {
roundTrip({ foo: { $val: 42 } }, { foo: 42 });
});

test('val_object', () => {
roundTrip(
{ foo: { $val: true, bar: 20 } },
{ foo: { bar: 20 } },
(decoded) => {
expect(decoded.foo.$val).toBe(true);
},
);
});

test('val_object_2', () => {
roundTrip(
{ foo: { $val: { bar: 20 } } },
{ foo: { bar: 20 } },
(decoded) => {
expect(decoded.foo.$val).toBe(true);
},
);
});

test('val_array', () => {
/** @type number[] & { $val?: true } */
const array = [1, 2, 3];
array.$val = true;
roundTrip({ foo: array }, { foo: [1, 2, 3] }, (decoded) => {
expect(decoded.foo.$val).toBe(true);
});
});

test('val_array_2', () => {
roundTrip({ foo: { $val: [1, 2, 3] } }, { foo: [1, 2, 3] }, (decoded) => {
expect(decoded.foo.$val).toBe(true);
});
});

test('point_deletion', () => {
roundTrip({ foo: null });
});
Expand Down
2 changes: 1 addition & 1 deletion src/common/ops/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function sliceNode(graph, query, result) {
}

export function sliceRange(graph, query, result) {
let { key, end, limit = Infinity, version } = query;
let { key, end, limit = Number.POSITIVE_INFINITY, version } = query;
const step = cmp(key, end) < 0 ? 1 : -1;

// Prefixes are used to combine filtering and pagination. In schemas where
Expand Down
4 changes: 2 additions & 2 deletions src/core/shift.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {
decodeGraph as origDecodeGraph,
decodeQuery as origDecodeQuery,
encodeGraph,
encodePath,
encodeQuery,
finalize,
merge,
mergeStreams,
decodeGraph as origDecodeGraph,
decodeQuery as origDecodeQuery,
remove,
unwrap,
unwrapObject,
Expand Down
6 changes: 3 additions & 3 deletions src/example/example.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { fork } from 'child_process';
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import { fork } from 'node:child_process';
import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { jest } from '@jest/globals';
import puppeteer from 'puppeteer';

Expand Down
2 changes: 1 addition & 1 deletion src/link/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
"version": "1.0.0",
"type": "module",
"main": "index.js"
}
}
4 changes: 2 additions & 2 deletions src/link/prepQueryLinks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ test('cube_args', () => {

const quantities = {
$ctd: [
[-Infinity, -Infinity],
[Infinity, Infinity],
[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY],
[Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY],
],
};

Expand Down
Loading

0 comments on commit 7e2c56a

Please sign in to comment.