@graffy/pg 0.16.8 → 0.16.9-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const common = require("@graffy/common");
4
- const pg$1 = require("pg");
5
4
  const debug = require("debug");
5
+ const pg$1 = require("pg");
6
6
  class Sql {
7
7
  constructor(rawStrings, rawValues) {
8
8
  if (rawStrings.length - 1 !== rawValues.length) {
@@ -298,14 +298,43 @@ function castValue(value, type, name, isPut) {
298
298
  return cubeLiteralSql(value);
299
299
  return value;
300
300
  }
301
- const getInsert = (row, options) => {
301
+ const getInsert = (rows, options) => {
302
+ const { verCol, schema } = options;
302
303
  const cols = [];
304
+ const colSqls = [];
305
+ const colIx = {};
306
+ const colUsed = [];
307
+ for (const col of Object.keys(options.schema.types)) {
308
+ colIx[col] = cols.length;
309
+ colUsed[cols.length] = false;
310
+ cols.push(col);
311
+ colSqls.push(sql`"${raw(col)}"`);
312
+ }
313
+ colUsed[colIx[verCol]] = true;
303
314
  const vals = [];
304
- Object.entries(row).filter(([col]) => col !== options.verCol && col[0] !== "$").concat([[options.verCol, sql`default`]]).forEach(([col, val]) => {
305
- cols.push(sql`"${raw(col)}"`);
306
- vals.push(castValue(val, options.schema.types[col], col, row.$put));
307
- });
308
- return { cols: join(cols, ", "), vals: join(vals, ", ") };
315
+ for (const row of rows) {
316
+ const rowVals = Array(cols.length).fill(sql`default`);
317
+ for (const col of cols) {
318
+ if (col === verCol || !(col in row))
319
+ continue;
320
+ const ix = colIx[col];
321
+ colUsed[ix] = true;
322
+ rowVals[ix] = castValue(row[col], schema.types[col], col, row.$put);
323
+ }
324
+ vals.push(rowVals);
325
+ }
326
+ const isUsed = (_, ix) => colUsed[ix];
327
+ return {
328
+ cols: join(colSqls.filter(isUsed), ", "),
329
+ vals: join(
330
+ vals.map((rowVals) => sql`(${join(rowVals.filter(isUsed), ", ")})`),
331
+ ", "
332
+ ),
333
+ updates: join(
334
+ colSqls.map((col, ix) => sql`${col} = "excluded".${col}`).filter(isUsed),
335
+ ", "
336
+ )
337
+ };
309
338
  };
310
339
  const getUpdates = (row, options) => {
311
340
  return join(
@@ -595,23 +624,35 @@ function patch(object, arg, options) {
595
624
  WHERE ${where}
596
625
  RETURNING ${getSelectCols(options)}, ${meta}`;
597
626
  }
598
- function put(object, arg, options) {
627
+ function put(puts, options) {
599
628
  const { idCol, table } = options;
600
- const row = object;
601
- let meta;
602
- let conflictTarget;
603
- if (common.isPlainObject(arg)) {
604
- ({ meta } = getArgSql(arg, options));
605
- conflictTarget = join(Object.keys(arg).map((col) => sql`"${raw(col)}"`));
606
- } else {
607
- meta = getIdMeta(options);
608
- conflictTarget = sql`"${raw(idCol)}"`;
629
+ const sqls = [];
630
+ const addSql = (rows, meta, conflictTarget) => {
631
+ const { cols, vals, updates } = getInsert(rows, options);
632
+ sqls.push(sql`
633
+ INSERT INTO "${raw(table)}" (${cols}) VALUES ${vals}
634
+ ON CONFLICT (${conflictTarget}) DO UPDATE SET ${updates}
635
+ RETURNING ${getSelectCols(options)}, ${meta}`);
636
+ };
637
+ const idRows = [];
638
+ for (const put2 of puts) {
639
+ const [row, arg] = put2;
640
+ if (!common.isPlainObject(arg)) {
641
+ idRows.push(row);
642
+ continue;
643
+ }
644
+ const { meta } = getArgSql(arg, options);
645
+ const conflictTarget = join(
646
+ Object.keys(arg).map((col) => sql`"${raw(col)}"`)
647
+ );
648
+ addSql([row], meta, conflictTarget);
609
649
  }
610
- const { cols, vals } = getInsert(row, options);
611
- return sql`
612
- INSERT INTO "${raw(table)}" (${cols}) VALUES (${vals})
613
- ON CONFLICT (${conflictTarget}) DO UPDATE SET (${cols}) = (${vals})
614
- RETURNING ${getSelectCols(options)}, ${meta}`;
650
+ if (idRows.length) {
651
+ const meta = getIdMeta(options);
652
+ const conflictTarget = sql`"${raw(idCol)}"`;
653
+ addSql(idRows, meta, conflictTarget);
654
+ }
655
+ return sqls;
615
656
  }
616
657
  function del(arg, options) {
617
658
  const { table } = options;
@@ -676,7 +717,7 @@ class Db {
676
717
  if (!res.rowCount) {
677
718
  throw Error(`pg.nothing_written ${sql2.text} with ${sql2.values}`);
678
719
  }
679
- return res.rows[0];
720
+ return res.rows;
680
721
  }
681
722
  async ensureSchema(tableOptions, typeOids) {
682
723
  if (tableOptions.schema)
@@ -740,11 +781,11 @@ class Db {
740
781
  selectByIds(Object.keys(idQueries), null, tableOptions),
741
782
  tableOptions
742
783
  );
743
- result.forEach((object) => {
784
+ for (const object of result) {
744
785
  const wrappedGraph = common.encodeGraph(common.wrapObject(object, rawPrefix));
745
786
  log("getByIds", wrappedGraph);
746
787
  common.merge(results, wrappedGraph);
747
- });
788
+ }
748
789
  };
749
790
  const query = common.unwrap(rootQuery, prefix);
750
791
  for (const node of query) {
@@ -775,28 +816,40 @@ class Db {
775
816
  const prefix = common.encodePath(rawPrefix);
776
817
  await this.ensureSchema(tableOptions);
777
818
  const change = common.unwrap(rootChange, prefix);
778
- const sqls = change.map((node) => {
819
+ const puts = [];
820
+ const sqls = [];
821
+ for (const node of change) {
779
822
  const arg = common.decodeArgs(node);
780
823
  if (common.isRange(node)) {
781
- if (common.cmp(node.key, node.end) === 0)
782
- return del(arg, tableOptions);
824
+ if (common.cmp(node.key, node.end) === 0) {
825
+ log("delete", node);
826
+ sqls.push(del(arg, tableOptions));
827
+ continue;
828
+ }
783
829
  throw Error("pg_write.write_range_unsupported");
784
830
  }
785
831
  const object = common.decodeGraph(node.children);
786
832
  if (common.isPlainObject(arg)) {
787
833
  common.mergeObject(object, arg);
788
834
  } else {
789
- object.id = arg;
835
+ object[tableOptions.idCol] = arg;
790
836
  }
791
837
  if (object.$put && object.$put !== true) {
792
838
  throw Error("pg_write.partial_put_unsupported");
793
839
  }
794
- return object.$put ? put(object, arg, tableOptions) : patch(object, arg, tableOptions);
795
- });
840
+ if (object.$put) {
841
+ puts.push([object, arg]);
842
+ } else {
843
+ sqls.push(patch(object, arg, tableOptions));
844
+ }
845
+ }
846
+ if (puts.length)
847
+ sqls.push(...put(puts, tableOptions));
796
848
  const result = [];
797
849
  await Promise.all(
798
850
  sqls.map(
799
851
  (sql2) => this.writeSql(sql2, tableOptions).then((object) => {
852
+ log("returned_object_wrapped", common.wrapObject(object, rawPrefix));
800
853
  common.merge(result, common.encodeGraph(common.wrapObject(object, rawPrefix)));
801
854
  })
802
855
  )
package/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { isEmpty, isPlainObject, encodePath, unwrap, decodeArgs, decodeQuery, finalize, wrap, isRange, cmp, decodeGraph, mergeObject, merge, encodeGraph, wrapObject, remove } from "@graffy/common";
2
- import pg$1 from "pg";
1
+ import { isEmpty, isPlainObject, encodePath, unwrap, decodeArgs, decodeQuery, finalize, wrap, isRange, cmp, decodeGraph, mergeObject, wrapObject, merge, encodeGraph, remove } from "@graffy/common";
3
2
  import debug from "debug";
3
+ import pg$1 from "pg";
4
4
  class Sql {
5
5
  constructor(rawStrings, rawValues) {
6
6
  if (rawStrings.length - 1 !== rawValues.length) {
@@ -296,14 +296,43 @@ function castValue(value, type, name, isPut) {
296
296
  return cubeLiteralSql(value);
297
297
  return value;
298
298
  }
299
- const getInsert = (row, options) => {
299
+ const getInsert = (rows, options) => {
300
+ const { verCol, schema } = options;
300
301
  const cols = [];
302
+ const colSqls = [];
303
+ const colIx = {};
304
+ const colUsed = [];
305
+ for (const col of Object.keys(options.schema.types)) {
306
+ colIx[col] = cols.length;
307
+ colUsed[cols.length] = false;
308
+ cols.push(col);
309
+ colSqls.push(sql`"${raw(col)}"`);
310
+ }
311
+ colUsed[colIx[verCol]] = true;
301
312
  const vals = [];
302
- Object.entries(row).filter(([col]) => col !== options.verCol && col[0] !== "$").concat([[options.verCol, sql`default`]]).forEach(([col, val]) => {
303
- cols.push(sql`"${raw(col)}"`);
304
- vals.push(castValue(val, options.schema.types[col], col, row.$put));
305
- });
306
- return { cols: join(cols, ", "), vals: join(vals, ", ") };
313
+ for (const row of rows) {
314
+ const rowVals = Array(cols.length).fill(sql`default`);
315
+ for (const col of cols) {
316
+ if (col === verCol || !(col in row))
317
+ continue;
318
+ const ix = colIx[col];
319
+ colUsed[ix] = true;
320
+ rowVals[ix] = castValue(row[col], schema.types[col], col, row.$put);
321
+ }
322
+ vals.push(rowVals);
323
+ }
324
+ const isUsed = (_, ix) => colUsed[ix];
325
+ return {
326
+ cols: join(colSqls.filter(isUsed), ", "),
327
+ vals: join(
328
+ vals.map((rowVals) => sql`(${join(rowVals.filter(isUsed), ", ")})`),
329
+ ", "
330
+ ),
331
+ updates: join(
332
+ colSqls.map((col, ix) => sql`${col} = "excluded".${col}`).filter(isUsed),
333
+ ", "
334
+ )
335
+ };
307
336
  };
308
337
  const getUpdates = (row, options) => {
309
338
  return join(
@@ -593,23 +622,35 @@ function patch(object, arg, options) {
593
622
  WHERE ${where}
594
623
  RETURNING ${getSelectCols(options)}, ${meta}`;
595
624
  }
596
- function put(object, arg, options) {
625
+ function put(puts, options) {
597
626
  const { idCol, table } = options;
598
- const row = object;
599
- let meta;
600
- let conflictTarget;
601
- if (isPlainObject(arg)) {
602
- ({ meta } = getArgSql(arg, options));
603
- conflictTarget = join(Object.keys(arg).map((col) => sql`"${raw(col)}"`));
604
- } else {
605
- meta = getIdMeta(options);
606
- conflictTarget = sql`"${raw(idCol)}"`;
627
+ const sqls = [];
628
+ const addSql = (rows, meta, conflictTarget) => {
629
+ const { cols, vals, updates } = getInsert(rows, options);
630
+ sqls.push(sql`
631
+ INSERT INTO "${raw(table)}" (${cols}) VALUES ${vals}
632
+ ON CONFLICT (${conflictTarget}) DO UPDATE SET ${updates}
633
+ RETURNING ${getSelectCols(options)}, ${meta}`);
634
+ };
635
+ const idRows = [];
636
+ for (const put2 of puts) {
637
+ const [row, arg] = put2;
638
+ if (!isPlainObject(arg)) {
639
+ idRows.push(row);
640
+ continue;
641
+ }
642
+ const { meta } = getArgSql(arg, options);
643
+ const conflictTarget = join(
644
+ Object.keys(arg).map((col) => sql`"${raw(col)}"`)
645
+ );
646
+ addSql([row], meta, conflictTarget);
607
647
  }
608
- const { cols, vals } = getInsert(row, options);
609
- return sql`
610
- INSERT INTO "${raw(table)}" (${cols}) VALUES (${vals})
611
- ON CONFLICT (${conflictTarget}) DO UPDATE SET (${cols}) = (${vals})
612
- RETURNING ${getSelectCols(options)}, ${meta}`;
648
+ if (idRows.length) {
649
+ const meta = getIdMeta(options);
650
+ const conflictTarget = sql`"${raw(idCol)}"`;
651
+ addSql(idRows, meta, conflictTarget);
652
+ }
653
+ return sqls;
613
654
  }
614
655
  function del(arg, options) {
615
656
  const { table } = options;
@@ -674,7 +715,7 @@ class Db {
674
715
  if (!res.rowCount) {
675
716
  throw Error(`pg.nothing_written ${sql2.text} with ${sql2.values}`);
676
717
  }
677
- return res.rows[0];
718
+ return res.rows;
678
719
  }
679
720
  async ensureSchema(tableOptions, typeOids) {
680
721
  if (tableOptions.schema)
@@ -738,11 +779,11 @@ class Db {
738
779
  selectByIds(Object.keys(idQueries), null, tableOptions),
739
780
  tableOptions
740
781
  );
741
- result.forEach((object) => {
782
+ for (const object of result) {
742
783
  const wrappedGraph = encodeGraph(wrapObject(object, rawPrefix));
743
784
  log("getByIds", wrappedGraph);
744
785
  merge(results, wrappedGraph);
745
- });
786
+ }
746
787
  };
747
788
  const query = unwrap(rootQuery, prefix);
748
789
  for (const node of query) {
@@ -773,28 +814,40 @@ class Db {
773
814
  const prefix = encodePath(rawPrefix);
774
815
  await this.ensureSchema(tableOptions);
775
816
  const change = unwrap(rootChange, prefix);
776
- const sqls = change.map((node) => {
817
+ const puts = [];
818
+ const sqls = [];
819
+ for (const node of change) {
777
820
  const arg = decodeArgs(node);
778
821
  if (isRange(node)) {
779
- if (cmp(node.key, node.end) === 0)
780
- return del(arg, tableOptions);
822
+ if (cmp(node.key, node.end) === 0) {
823
+ log("delete", node);
824
+ sqls.push(del(arg, tableOptions));
825
+ continue;
826
+ }
781
827
  throw Error("pg_write.write_range_unsupported");
782
828
  }
783
829
  const object = decodeGraph(node.children);
784
830
  if (isPlainObject(arg)) {
785
831
  mergeObject(object, arg);
786
832
  } else {
787
- object.id = arg;
833
+ object[tableOptions.idCol] = arg;
788
834
  }
789
835
  if (object.$put && object.$put !== true) {
790
836
  throw Error("pg_write.partial_put_unsupported");
791
837
  }
792
- return object.$put ? put(object, arg, tableOptions) : patch(object, arg, tableOptions);
793
- });
838
+ if (object.$put) {
839
+ puts.push([object, arg]);
840
+ } else {
841
+ sqls.push(patch(object, arg, tableOptions));
842
+ }
843
+ }
844
+ if (puts.length)
845
+ sqls.push(...put(puts, tableOptions));
794
846
  const result = [];
795
847
  await Promise.all(
796
848
  sqls.map(
797
849
  (sql2) => this.writeSql(sql2, tableOptions).then((object) => {
850
+ log("returned_object_wrapped", wrapObject(object, rawPrefix));
798
851
  merge(result, encodeGraph(wrapObject(object, rawPrefix)));
799
852
  })
800
853
  )
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graffy/pg",
3
3
  "description": "The standard Postgres module for Graffy. Each instance this module mounts a Postgres table as a Graffy subtree.",
4
4
  "author": "aravind (https://github.com/aravindet)",
5
- "version": "0.16.8",
5
+ "version": "0.16.9-alpha.2",
6
6
  "main": "./index.cjs",
7
7
  "exports": {
8
8
  "import": "./index.mjs",
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "license": "Apache-2.0",
18
18
  "dependencies": {
19
- "@graffy/common": "0.16.8",
19
+ "@graffy/common": "0.16.9-alpha.2",
20
20
  "debug": "^4.3.3"
21
21
  },
22
22
  "peerDependencies": {
@@ -3,9 +3,10 @@ export function getJsonBuildTrusted(variadic: any): Sql;
3
3
  export function lookup(prop: any, options: any): Sql;
4
4
  export function lookupNumeric(prop: any): Sql;
5
5
  export function getSelectCols(options: any, projection?: any): Sql;
6
- export function getInsert(row: any, options: any): {
6
+ export function getInsert(rows: any, options: any): {
7
7
  cols: Sql;
8
8
  vals: Sql;
9
+ updates: Sql;
9
10
  };
10
11
  export function getUpdates(row: any, options: any): Sql;
11
12
  import { Sql } from "sql-template-tag";
@@ -1,3 +1,3 @@
1
1
  export function patch(object: any, arg: any, options: any): import("sql-template-tag").Sql;
2
- export function put(object: any, arg: any, options: any): import("sql-template-tag").Sql;
2
+ export function put(puts: any, options: any): any[];
3
3
  export function del(arg: any, options: any): import("sql-template-tag").Sql;