@graffy/pg 0.16.8 → 0.16.9-alpha.1

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,44 @@ 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(null);
317
+ rowVals[colIx[verCol]] = sql`default`;
318
+ for (const col of cols) {
319
+ if (col === verCol || !(col in row))
320
+ continue;
321
+ const ix = colIx[col];
322
+ colUsed[ix] = true;
323
+ rowVals[ix] = castValue(row[col], schema.types[col], col, row.$put);
324
+ }
325
+ vals.push(rowVals);
326
+ }
327
+ const isUsed = (_, ix) => colUsed[ix];
328
+ return {
329
+ cols: join(colSqls.filter(isUsed), ", "),
330
+ vals: join(
331
+ vals.map((rowVals) => sql`(${join(rowVals.filter(isUsed), ", ")})`),
332
+ ", "
333
+ ),
334
+ updates: join(
335
+ colSqls.map((col, ix) => sql`${col} = "excluded".${col}`).filter(isUsed),
336
+ ", "
337
+ )
338
+ };
309
339
  };
310
340
  const getUpdates = (row, options) => {
311
341
  return join(
@@ -595,23 +625,35 @@ function patch(object, arg, options) {
595
625
  WHERE ${where}
596
626
  RETURNING ${getSelectCols(options)}, ${meta}`;
597
627
  }
598
- function put(object, arg, options) {
628
+ function put(puts, options) {
599
629
  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)}"`;
630
+ const sqls = [];
631
+ const addSql = (rows, meta, conflictTarget) => {
632
+ const { cols, vals, updates } = getInsert(rows, options);
633
+ sqls.push(sql`
634
+ INSERT INTO "${raw(table)}" (${cols}) VALUES ${vals}
635
+ ON CONFLICT (${conflictTarget}) DO UPDATE SET ${updates}
636
+ RETURNING ${getSelectCols(options)}, ${meta}`);
637
+ };
638
+ const idRows = [];
639
+ for (const put2 of puts) {
640
+ const [row, arg] = put2;
641
+ if (!common.isPlainObject(arg)) {
642
+ idRows.push(row);
643
+ continue;
644
+ }
645
+ const { meta } = getArgSql(arg, options);
646
+ const conflictTarget = join(
647
+ Object.keys(arg).map((col) => sql`"${raw(col)}"`)
648
+ );
649
+ addSql([row], meta, conflictTarget);
609
650
  }
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}`;
651
+ if (idRows.length) {
652
+ const meta = getIdMeta(options);
653
+ const conflictTarget = sql`"${raw(idCol)}"`;
654
+ addSql(idRows, meta, conflictTarget);
655
+ }
656
+ return sqls;
615
657
  }
616
658
  function del(arg, options) {
617
659
  const { table } = options;
@@ -676,7 +718,7 @@ class Db {
676
718
  if (!res.rowCount) {
677
719
  throw Error(`pg.nothing_written ${sql2.text} with ${sql2.values}`);
678
720
  }
679
- return res.rows[0];
721
+ return res.rows;
680
722
  }
681
723
  async ensureSchema(tableOptions, typeOids) {
682
724
  if (tableOptions.schema)
@@ -740,11 +782,11 @@ class Db {
740
782
  selectByIds(Object.keys(idQueries), null, tableOptions),
741
783
  tableOptions
742
784
  );
743
- result.forEach((object) => {
785
+ for (const object of result) {
744
786
  const wrappedGraph = common.encodeGraph(common.wrapObject(object, rawPrefix));
745
787
  log("getByIds", wrappedGraph);
746
788
  common.merge(results, wrappedGraph);
747
- });
789
+ }
748
790
  };
749
791
  const query = common.unwrap(rootQuery, prefix);
750
792
  for (const node of query) {
@@ -775,28 +817,40 @@ class Db {
775
817
  const prefix = common.encodePath(rawPrefix);
776
818
  await this.ensureSchema(tableOptions);
777
819
  const change = common.unwrap(rootChange, prefix);
778
- const sqls = change.map((node) => {
820
+ const puts = [];
821
+ const sqls = [];
822
+ for (const node of change) {
779
823
  const arg = common.decodeArgs(node);
780
824
  if (common.isRange(node)) {
781
- if (common.cmp(node.key, node.end) === 0)
782
- return del(arg, tableOptions);
825
+ if (common.cmp(node.key, node.end) === 0) {
826
+ log("delete", node);
827
+ sqls.push(del(arg, tableOptions));
828
+ continue;
829
+ }
783
830
  throw Error("pg_write.write_range_unsupported");
784
831
  }
785
832
  const object = common.decodeGraph(node.children);
786
833
  if (common.isPlainObject(arg)) {
787
834
  common.mergeObject(object, arg);
788
835
  } else {
789
- object.id = arg;
836
+ object[tableOptions.idCol] = arg;
790
837
  }
791
838
  if (object.$put && object.$put !== true) {
792
839
  throw Error("pg_write.partial_put_unsupported");
793
840
  }
794
- return object.$put ? put(object, arg, tableOptions) : patch(object, arg, tableOptions);
795
- });
841
+ if (object.$put) {
842
+ puts.push([object, arg]);
843
+ } else {
844
+ sqls.push(patch(object, arg, tableOptions));
845
+ }
846
+ }
847
+ if (puts.length)
848
+ sqls.push(...put(puts, tableOptions));
796
849
  const result = [];
797
850
  await Promise.all(
798
851
  sqls.map(
799
852
  (sql2) => this.writeSql(sql2, tableOptions).then((object) => {
853
+ log("returned_object_wrapped", common.wrapObject(object, rawPrefix));
800
854
  common.merge(result, common.encodeGraph(common.wrapObject(object, rawPrefix)));
801
855
  })
802
856
  )
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,44 @@ 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(null);
315
+ rowVals[colIx[verCol]] = sql`default`;
316
+ for (const col of cols) {
317
+ if (col === verCol || !(col in row))
318
+ continue;
319
+ const ix = colIx[col];
320
+ colUsed[ix] = true;
321
+ rowVals[ix] = castValue(row[col], schema.types[col], col, row.$put);
322
+ }
323
+ vals.push(rowVals);
324
+ }
325
+ const isUsed = (_, ix) => colUsed[ix];
326
+ return {
327
+ cols: join(colSqls.filter(isUsed), ", "),
328
+ vals: join(
329
+ vals.map((rowVals) => sql`(${join(rowVals.filter(isUsed), ", ")})`),
330
+ ", "
331
+ ),
332
+ updates: join(
333
+ colSqls.map((col, ix) => sql`${col} = "excluded".${col}`).filter(isUsed),
334
+ ", "
335
+ )
336
+ };
307
337
  };
308
338
  const getUpdates = (row, options) => {
309
339
  return join(
@@ -593,23 +623,35 @@ function patch(object, arg, options) {
593
623
  WHERE ${where}
594
624
  RETURNING ${getSelectCols(options)}, ${meta}`;
595
625
  }
596
- function put(object, arg, options) {
626
+ function put(puts, options) {
597
627
  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)}"`;
628
+ const sqls = [];
629
+ const addSql = (rows, meta, conflictTarget) => {
630
+ const { cols, vals, updates } = getInsert(rows, options);
631
+ sqls.push(sql`
632
+ INSERT INTO "${raw(table)}" (${cols}) VALUES ${vals}
633
+ ON CONFLICT (${conflictTarget}) DO UPDATE SET ${updates}
634
+ RETURNING ${getSelectCols(options)}, ${meta}`);
635
+ };
636
+ const idRows = [];
637
+ for (const put2 of puts) {
638
+ const [row, arg] = put2;
639
+ if (!isPlainObject(arg)) {
640
+ idRows.push(row);
641
+ continue;
642
+ }
643
+ const { meta } = getArgSql(arg, options);
644
+ const conflictTarget = join(
645
+ Object.keys(arg).map((col) => sql`"${raw(col)}"`)
646
+ );
647
+ addSql([row], meta, conflictTarget);
607
648
  }
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}`;
649
+ if (idRows.length) {
650
+ const meta = getIdMeta(options);
651
+ const conflictTarget = sql`"${raw(idCol)}"`;
652
+ addSql(idRows, meta, conflictTarget);
653
+ }
654
+ return sqls;
613
655
  }
614
656
  function del(arg, options) {
615
657
  const { table } = options;
@@ -674,7 +716,7 @@ class Db {
674
716
  if (!res.rowCount) {
675
717
  throw Error(`pg.nothing_written ${sql2.text} with ${sql2.values}`);
676
718
  }
677
- return res.rows[0];
719
+ return res.rows;
678
720
  }
679
721
  async ensureSchema(tableOptions, typeOids) {
680
722
  if (tableOptions.schema)
@@ -738,11 +780,11 @@ class Db {
738
780
  selectByIds(Object.keys(idQueries), null, tableOptions),
739
781
  tableOptions
740
782
  );
741
- result.forEach((object) => {
783
+ for (const object of result) {
742
784
  const wrappedGraph = encodeGraph(wrapObject(object, rawPrefix));
743
785
  log("getByIds", wrappedGraph);
744
786
  merge(results, wrappedGraph);
745
- });
787
+ }
746
788
  };
747
789
  const query = unwrap(rootQuery, prefix);
748
790
  for (const node of query) {
@@ -773,28 +815,40 @@ class Db {
773
815
  const prefix = encodePath(rawPrefix);
774
816
  await this.ensureSchema(tableOptions);
775
817
  const change = unwrap(rootChange, prefix);
776
- const sqls = change.map((node) => {
818
+ const puts = [];
819
+ const sqls = [];
820
+ for (const node of change) {
777
821
  const arg = decodeArgs(node);
778
822
  if (isRange(node)) {
779
- if (cmp(node.key, node.end) === 0)
780
- return del(arg, tableOptions);
823
+ if (cmp(node.key, node.end) === 0) {
824
+ log("delete", node);
825
+ sqls.push(del(arg, tableOptions));
826
+ continue;
827
+ }
781
828
  throw Error("pg_write.write_range_unsupported");
782
829
  }
783
830
  const object = decodeGraph(node.children);
784
831
  if (isPlainObject(arg)) {
785
832
  mergeObject(object, arg);
786
833
  } else {
787
- object.id = arg;
834
+ object[tableOptions.idCol] = arg;
788
835
  }
789
836
  if (object.$put && object.$put !== true) {
790
837
  throw Error("pg_write.partial_put_unsupported");
791
838
  }
792
- return object.$put ? put(object, arg, tableOptions) : patch(object, arg, tableOptions);
793
- });
839
+ if (object.$put) {
840
+ puts.push([object, arg]);
841
+ } else {
842
+ sqls.push(patch(object, arg, tableOptions));
843
+ }
844
+ }
845
+ if (puts.length)
846
+ sqls.push(...put(puts, tableOptions));
794
847
  const result = [];
795
848
  await Promise.all(
796
849
  sqls.map(
797
850
  (sql2) => this.writeSql(sql2, tableOptions).then((object) => {
851
+ log("returned_object_wrapped", wrapObject(object, rawPrefix));
798
852
  merge(result, encodeGraph(wrapObject(object, rawPrefix)));
799
853
  })
800
854
  )
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.1",
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.1",
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;