prostgles-server 2.0.187 → 2.0.188

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.
Files changed (75) hide show
  1. package/dist/DboBuilder/insert.d.ts +5 -0
  2. package/dist/DboBuilder/insert.d.ts.map +1 -0
  3. package/dist/DboBuilder/insert.js +129 -0
  4. package/dist/DboBuilder/insert.js.map +1 -0
  5. package/dist/DboBuilder/insertDataParse.d.ts +11 -0
  6. package/dist/DboBuilder/insertDataParse.d.ts.map +1 -0
  7. package/dist/DboBuilder/insertDataParse.js +283 -0
  8. package/dist/DboBuilder/insertDataParse.js.map +1 -0
  9. package/dist/DboBuilder.d.ts +10 -5
  10. package/dist/DboBuilder.d.ts.map +1 -1
  11. package/dist/DboBuilder.js +105 -365
  12. package/dist/DboBuilder.js.map +1 -1
  13. package/dist/FileManager.d.ts.map +1 -1
  14. package/dist/FileManager.js +17 -12
  15. package/dist/FileManager.js.map +1 -1
  16. package/dist/Prostgles.d.ts +1 -1
  17. package/dist/Prostgles.d.ts.map +1 -1
  18. package/dist/Prostgles.js.map +1 -1
  19. package/dist/QueryBuilder.d.ts.map +1 -1
  20. package/dist/QueryBuilder.js +7 -2
  21. package/dist/QueryBuilder.js.map +1 -1
  22. package/dist/TableConfig.d.ts +1 -4
  23. package/dist/TableConfig.d.ts.map +1 -1
  24. package/dist/TableConfig.js.map +1 -1
  25. package/lib/DboBuilder/insert.d.ts +5 -0
  26. package/lib/DboBuilder/insert.d.ts.map +1 -0
  27. package/lib/DboBuilder/insert.js +128 -0
  28. package/lib/DboBuilder/insert.ts +138 -0
  29. package/lib/DboBuilder/insertDataParse.d.ts +11 -0
  30. package/lib/DboBuilder/insertDataParse.d.ts.map +1 -0
  31. package/lib/DboBuilder/insertDataParse.js +282 -0
  32. package/lib/DboBuilder/insertDataParse.ts +355 -0
  33. package/lib/DboBuilder.d.ts +10 -5
  34. package/lib/DboBuilder.d.ts.map +1 -1
  35. package/lib/DboBuilder.js +105 -365
  36. package/lib/DboBuilder.ts +121 -440
  37. package/lib/FileManager.d.ts.map +1 -1
  38. package/lib/FileManager.js +17 -12
  39. package/lib/FileManager.ts +18 -13
  40. package/lib/Prostgles.d.ts +1 -1
  41. package/lib/Prostgles.d.ts.map +1 -1
  42. package/lib/Prostgles.ts +664 -652
  43. package/lib/QueryBuilder.d.ts.map +1 -1
  44. package/lib/QueryBuilder.js +7 -2
  45. package/lib/QueryBuilder.ts +12 -7
  46. package/lib/TableConfig.d.ts +1 -4
  47. package/lib/TableConfig.d.ts.map +1 -1
  48. package/lib/TableConfig.ts +2 -6
  49. package/package.json +2 -2
  50. package/tests/client/PID.txt +1 -1
  51. package/tests/client/tsconfig.json +1 -1
  52. package/tests/client_only_queries.d.ts +1 -1
  53. package/tests/client_only_queries.d.ts.map +1 -1
  54. package/tests/client_only_queries.ts +1 -1
  55. package/tests/isomorphic_queries.d.ts +1 -1
  56. package/tests/isomorphic_queries.d.ts.map +1 -1
  57. package/tests/isomorphic_queries.js +48 -1
  58. package/tests/isomorphic_queries.ts +65 -4
  59. package/tests/manual_test/DBoGenerated.d.ts +398 -0
  60. package/tests/manual_test/index.d.ts +2 -0
  61. package/tests/manual_test/index.d.ts.map +1 -0
  62. package/tests/{config_test2 → manual_test}/index.html +14 -23
  63. package/tests/{config_test2 → manual_test}/index.js +21 -15
  64. package/tests/{config_test2 → manual_test}/index.ts +22 -17
  65. package/tests/{config_test2 → manual_test}/init.sql +36 -5
  66. package/tests/manual_test/package-lock.json +2483 -0
  67. package/tests/{config_test2 → manual_test}/package.json +6 -7
  68. package/tests/manual_test/tsconfig.json +21 -0
  69. package/tests/server/DBoGenerated.d.ts +70 -0
  70. package/tests/server/index.js +29 -2
  71. package/tests/server/index.ts +30 -4
  72. package/tests/server/init.sql +25 -0
  73. package/tests/server/package-lock.json +3 -3
  74. package/tests/config_test2/DBoGenerated.d.ts +0 -135
  75. package/tests/config_test2/tsconfig.json +0 -21
@@ -5,7 +5,7 @@
5
5
  *--------------------------------------------------------------------------------------------*/
6
6
  var _a;
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.postgresToTsType = exports.isPlainObject = exports.DboBuilder = exports.TableHandler = exports.ViewHandler = exports.EXISTS_KEYS = exports.escapeTSNames = exports.pgp = exports.getUpdateFilter = void 0;
8
+ exports.postgresToTsType = exports.isPlainObject = exports.DboBuilder = exports.TableHandler = exports.isPojoObject = exports.ViewHandler = exports.parseError = exports.EXISTS_KEYS = exports.makeErr = exports.escapeTSNames = exports.pgp = exports.getUpdateFilter = void 0;
9
9
  const Bluebird = require("bluebird");
10
10
  // declare global { export interface Promise<T> extends Bluebird<T> {} }
11
11
  const pgPromise = require("pg-promise");
@@ -25,6 +25,8 @@ exports.getUpdateFilter = getUpdateFilter;
25
25
  const utils_1 = require("./utils");
26
26
  const QueryBuilder_1 = require("./QueryBuilder");
27
27
  const PubSubManager_1 = require("./PubSubManager");
28
+ const insertDataParse_1 = require("./DboBuilder/insertDataParse");
29
+ const insert_1 = require("./DboBuilder/insert");
28
30
  const Filtering_1 = require("./Filtering");
29
31
  exports.pgp = pgPromise({
30
32
  promiseLib: Bluebird
@@ -96,15 +98,17 @@ function makeErr(err, localParams, view, allowedKeys) {
96
98
  }
97
99
  return Promise.reject(errObject);
98
100
  }
101
+ exports.makeErr = makeErr;
99
102
  exports.EXISTS_KEYS = ["$exists", "$notExists", "$existsJoined", "$notExistsJoined"];
100
103
  const FILTER_FUNCS = QueryBuilder_1.FUNCTIONS.filter(f => f.canBeUsedForFilter);
101
104
  function parseError(e) {
102
105
  // console.trace("INTERNAL ERROR: ", e);
103
- let res = (!Object.keys(e || {}).length ? e : (e && e.toString) ? e.toString() : e);
106
+ let res = e instanceof Error ? e.message : (!Object.keys(e || {}).length ? e : (e && e.toString) ? e.toString() : e);
104
107
  if (isPlainObject(e))
105
108
  res = JSON.stringify(e, null, 2);
106
109
  return res;
107
110
  }
111
+ exports.parseError = parseError;
108
112
  class ColSet {
109
113
  constructor(columns, tableName) {
110
114
  this.opts = { columns, tableName, colNames: columns.map(c => c.name) };
@@ -292,12 +296,15 @@ class ViewHandler {
292
296
  // let searchedTables = [], result;
293
297
  // while (!result && searchedTables.length <= this.joins.length * 2){
294
298
  // }
299
+ const getJoinCondition = (on, leftTable, rightTable) => {
300
+ return on.map(cond => Object.keys(cond).map(lKey => `${leftTable}.${lKey} = ${rightTable}.${cond[lKey]}`).join("\nAND ")).join(" OR ");
301
+ };
295
302
  let toOne = true, query = this.joins.map(({ tables, on, type }, i) => {
296
303
  if (type.split("-")[1] === "many") {
297
304
  toOne = false;
298
305
  }
299
306
  const tl = `tl${startAlias + i}`, tr = `tr${startAlias + i}`;
300
- return `FROM ${tables[0]} ${tl} ${isInner ? "INNER" : "LEFT"} JOIN ${tables[1]} ${tr} ON ${Object.keys(on).map(lKey => `${tl}.${lKey} = ${tr}.${on[lKey]}`).join("\nAND ")}`;
307
+ return `FROM ${tables[0]} ${tl} ${isInner ? "INNER" : "LEFT"} JOIN ${tables[1]} ${tr} ON ${getJoinCondition(on, tl, tr)}`;
301
308
  }).join("\n");
302
309
  return { query, toOne: false };
303
310
  }
@@ -337,16 +344,20 @@ class ViewHandler {
337
344
  throw `Joining ${t1} <-> ${t2} dissallowed or missing`;
338
345
  ;
339
346
  let on = [];
340
- Object.keys(jo.on).map(leftKey => {
341
- const rightKey = jo.on[leftKey];
342
- /* Left table is joining on keys */
343
- if (jo.tables[0] === t1) {
344
- on.push([leftKey, rightKey]);
345
- /* Left table is joining on values */
346
- }
347
- else {
348
- on.push([rightKey, leftKey]);
349
- }
347
+ jo.on.map(cond => {
348
+ let condArr = [];
349
+ Object.keys(cond).map(leftKey => {
350
+ const rightKey = cond[leftKey];
351
+ /* Left table is joining on keys */
352
+ if (jo.tables[0] === t1) {
353
+ condArr.push([leftKey, rightKey]);
354
+ /* Left table is joining on values */
355
+ }
356
+ else {
357
+ condArr.push([rightKey, leftKey]);
358
+ }
359
+ });
360
+ on.push(condArr);
350
361
  });
351
362
  return {
352
363
  source,
@@ -676,7 +687,8 @@ class ViewHandler {
676
687
  // console.trace(e)
677
688
  if (localParams && localParams.testRule)
678
689
  throw e;
679
- throw { err: parseError(e), msg: `Issue with dbo.${this.name}.find(${JSON.stringify(filter || {}, null, 2)}, ${JSON.stringify(selectParams || {}, null, 2)})` };
690
+ // ${JSON.stringify(filter || {}, null, 2)}, ${JSON.stringify(selectParams || {}, null, 2)}
691
+ throw { err: parseError(e), msg: `Issue with dbo.${this.name}.find()`, args: { filter, selectParams } };
680
692
  }
681
693
  }
682
694
  findOne(filter, selectParams, param3_unused, table_rules, localParams) {
@@ -865,7 +877,9 @@ class ViewHandler {
865
877
  let table = paths[ji].table;
866
878
  let tableAlias = (0, prostgles_types_1.asName)(ji < paths.length - 1 ? `jd${ji}` : table);
867
879
  let prevTableAlias = (0, prostgles_types_1.asName)(ji ? `jd${ji - 1}` : thisTable);
868
- let cond = `${jp.on.map(([c1, c2]) => `${prevTableAlias}.${(0, prostgles_types_1.asName)(c1)} = ${tableAlias}.${(0, prostgles_types_1.asName)(c2)}`).join("\n AND ")}`;
880
+ let cond = `${jp.on.map(c => {
881
+ return c.map(([c1, c2]) => `${prevTableAlias}.${(0, prostgles_types_1.asName)(c1)} = ${tableAlias}.${(0, prostgles_types_1.asName)(c2)}`).join(" AND ");
882
+ }).join("\n OR ")}`;
869
883
  let j = `SELECT 1 \n` +
870
884
  `FROM ${(0, prostgles_types_1.asName)(table)} ${tableAlias} \n` +
871
885
  `WHERE ${cond} \n`; //
@@ -1393,9 +1407,11 @@ function isPojoObject(obj) {
1393
1407
  }
1394
1408
  return true;
1395
1409
  }
1410
+ exports.isPojoObject = isPojoObject;
1396
1411
  class TableHandler extends ViewHandler {
1397
1412
  constructor(db, tableOrViewInfo, dboBuilder, t, dbTX, joinPaths) {
1398
1413
  super(db, tableOrViewInfo, dboBuilder, t, dbTX, joinPaths);
1414
+ this.insertDataParse = insertDataParse_1.insertDataParse;
1399
1415
  this.prepareReturning = async (returning, allowedFields) => {
1400
1416
  let result = [];
1401
1417
  if (returning) {
@@ -1717,321 +1733,9 @@ class TableHandler extends ViewHandler {
1717
1733
  });
1718
1734
  return { data, allowedCols: this.columns.filter(c => dataKeys.includes(c.name)).map(c => c.name) };
1719
1735
  }
1720
- async insertDataParse(data, param2, param3_unused, tableRules, _localParams) {
1721
- const localParams = _localParams || {};
1722
- let dbTX = localParams?.dbTX || this.dbTX;
1723
- const isMultiInsert = Array.isArray(data);
1724
- const getExtraKeys = (d) => Object.keys(d).filter(k => !this.columns.find(c => c.name === k));
1725
- /* Nested insert is not allowed for the file table */
1726
- const isNestedInsert = this.is_media ? false : (Array.isArray(data) ? data : [data]).some(d => getExtraKeys(d).length);
1727
- /**
1728
- * Make sure nested insert uses a transaction
1729
- */
1730
- if (isNestedInsert && !dbTX) {
1731
- return {
1732
- insertResult: await this.dboBuilder.getTX((dbTX) => dbTX[this.name].insert(data, param2, param3_unused, tableRules, { dbTX, ...localParams }))
1733
- };
1734
- }
1735
- // if(!dbTX && this.t) dbTX = this.d;
1736
- const preValidate = tableRules?.insert?.preValidate, validate = tableRules?.insert?.validate;
1737
- let _data = await Promise.all((Array.isArray(data) ? data : [data]).map(async (row) => {
1738
- if (preValidate) {
1739
- row = await preValidate(row);
1740
- }
1741
- const dataKeys = Object.keys(row);
1742
- const extraKeys = getExtraKeys(row);
1743
- /* Upload file then continue insert */
1744
- if (this.is_media) {
1745
- if (!this.dboBuilder.prostgles?.fileManager)
1746
- throw "fileManager not set up";
1747
- const { data, name } = row;
1748
- if (dataKeys.length !== 2)
1749
- throw "Expecting only two properties: { name: string; data: File }";
1750
- // if(!Buffer.isBuffer(data)) throw "data is not of type Buffer"
1751
- if (!data)
1752
- throw "data not provided";
1753
- if (typeof name !== "string") {
1754
- throw "name is not of type string";
1755
- }
1756
- const media_id = (await this.db.oneOrNone("SELECT gen_random_uuid() as name")).name;
1757
- const type = await this.dboBuilder.prostgles.fileManager.getMIME(data, name);
1758
- const media_name = `${media_id}.${type.ext}`;
1759
- let media = {
1760
- id: media_id,
1761
- name: media_name,
1762
- original_name: name,
1763
- extension: type.ext,
1764
- content_type: type.mime
1765
- };
1766
- if (validate) {
1767
- media = await validate(media);
1768
- }
1769
- const _media = await this.dboBuilder.prostgles.fileManager.uploadAsMedia({
1770
- item: {
1771
- data,
1772
- name: media.name ?? "????",
1773
- content_type: media.content_type
1774
- },
1775
- // imageCompression: {
1776
- // inside: {
1777
- // width: 1100,
1778
- // height: 630
1779
- // }
1780
- // }
1781
- });
1782
- return {
1783
- ...media,
1784
- ..._media,
1785
- };
1786
- /* Potentially a nested join */
1787
- }
1788
- else if (extraKeys.length) {
1789
- /* Ensure we're using the same transaction */
1790
- const _this = this.t ? this : dbTX[this.name];
1791
- let rootData = Array.isArray(data) ? data.map(d => (0, PubSubManager_1.omitKeys)(d, extraKeys)) : (0, PubSubManager_1.omitKeys)(data, extraKeys);
1792
- let insertedChildren;
1793
- let targetTableRules;
1794
- const fullRootResult = await _this.insert(rootData, { returning: "*" }, undefined, tableRules, localParams);
1795
- let returnData;
1796
- const returning = param2?.returning;
1797
- if (returning) {
1798
- returnData = {};
1799
- const returningItems = await this.prepareReturning(returning, this.parseFieldFilter(tableRules?.insert?.returningFields));
1800
- returningItems.filter(s => s.selected).map(rs => {
1801
- returnData[rs.alias] = fullRootResult[rs.alias];
1802
- });
1803
- }
1804
- await Promise.all(extraKeys.map(async (targetTable) => {
1805
- const childDataItems = Array.isArray(row[targetTable]) ? row[targetTable] : [row[targetTable]];
1806
- /* Must be allowed to insert into media table */
1807
- const canInsert = async (tbl) => {
1808
- const childRules = await this.dboBuilder.publishParser?.getValidatedRequestRuleWusr({ tableName: tbl, command: "insert", localParams });
1809
- if (!childRules || !childRules.insert)
1810
- throw "Dissallowed nested insert into table " + childRules;
1811
- return childRules;
1812
- };
1813
- // console.log(JSON.stringify(this.dboBuilder.joinPaths, null, 2))
1814
- const jp = this.dboBuilder.joinPaths.find(jp => jp.t1 === this.name && jp.t2 === targetTable);
1815
- if (!jp)
1816
- throw `Could not find a valid table for the nested data { ${targetTable} } `;
1817
- const thisInfo = await this.getInfo();
1818
- const childInsert = async (cdata, tableName) => {
1819
- // console.log("childInsert", {data, tableName})
1820
- if (!cdata || !dbTX?.[tableName] || !("insert" in dbTX[tableName]))
1821
- throw "childInsertErr: Child table handler missing for: " + tableName;
1822
- const tableRules = await canInsert(tableName);
1823
- if (thisInfo.has_media === "one" && thisInfo.media_table_name === tableName && Array.isArray(cdata) && cdata.length > 1) {
1824
- throw "Constraint check fail: Cannot insert more than one record into " + JSON.stringify(tableName);
1825
- }
1826
- return Promise.all((Array.isArray(cdata) ? cdata : [cdata])
1827
- .map(m => dbTX[tableName]
1828
- .insert(m, { returning: "*" }, undefined, tableRules, localParams)
1829
- .catch(e => {
1830
- console.trace({ childInsertErr: e });
1831
- return Promise.reject({ childInsertErr: e });
1832
- })));
1833
- };
1834
- const { path } = jp;
1835
- const [tbl1, tbl2, tbl3] = path;
1836
- targetTableRules = await canInsert(targetTable); // tbl3
1837
- const cols2 = this.dboBuilder.dbo[tbl2].columns || [];
1838
- if (!this.dboBuilder.dbo[tbl2])
1839
- throw "Invalid/disallowed table: " + tbl2;
1840
- const colsRefT1 = cols2?.filter(c => c.references?.cols.length === 1 && c.references?.ftable === tbl1);
1841
- if (!path.length) {
1842
- throw "Nested inserts join path not found for " + [this.name, targetTable];
1843
- }
1844
- else if (path.length === 2) {
1845
- if (targetTable !== tbl2)
1846
- throw "Did not expect this";
1847
- if (!colsRefT1.length)
1848
- throw `Target table ${tbl2} does not reference any columns from the root table ${this.name}. Cannot do nested insert`;
1849
- // console.log(childDataItems, JSON.stringify(colsRefT1, null, 2))
1850
- insertedChildren = await childInsert(childDataItems.map((d) => {
1851
- let result = { ...d };
1852
- colsRefT1.map(col => {
1853
- result[col.references.cols[0]] = fullRootResult[col.references.fcols[0]];
1854
- });
1855
- return result;
1856
- }), targetTable);
1857
- // console.log({ insertedChildren })
1858
- }
1859
- else if (path.length === 3) {
1860
- if (targetTable !== tbl3)
1861
- throw "Did not expect this";
1862
- const colsRefT3 = cols2?.filter(c => c.references?.cols.length === 1 && c.references?.ftable === tbl3);
1863
- if (!colsRefT1.length || !colsRefT3.length)
1864
- throw "Incorrectly referenced or missing columns for nested insert";
1865
- if (targetTable !== this.dboBuilder.prostgles.fileManager?.tableName) {
1866
- throw "Only media allowed to have nested inserts more than 2 tables apart";
1867
- }
1868
- /* We expect tbl2 to have only 2 columns (media_id and foreign_id) */
1869
- if (!cols2 || cols2.find(c => !["media_id", "foreign_id"].includes(c.name))) {
1870
- throw "Second joining table not of expected format";
1871
- }
1872
- insertedChildren = await childInsert(childDataItems, targetTable);
1873
- /* Insert in key_lookup table */
1874
- await Promise.all(insertedChildren.map(async (t3Child) => {
1875
- let tbl2Row = {};
1876
- colsRefT3.map(col => {
1877
- tbl2Row[col.name] = t3Child[col.references.fcols[0]];
1878
- });
1879
- colsRefT1.map(col => {
1880
- tbl2Row[col.name] = fullRootResult[col.references.fcols[0]];
1881
- });
1882
- // console.log({ rootResult, tbl2Row, t3Child, colsRefT3, colsRefT1, t: this.t?.ctx?.start });
1883
- await childInsert(tbl2Row, tbl2); //.then(() => {});
1884
- }));
1885
- }
1886
- else {
1887
- console.error(JSON.stringify({ path, thisTable: this.name, targetTable }, null, 2));
1888
- throw "Unexpected path for Nested inserts";
1889
- }
1890
- /* Return also the nested inserted data */
1891
- if (targetTableRules && insertedChildren?.length && returning) {
1892
- const targetTableHandler = dbTX[targetTable];
1893
- const targetReturning = await targetTableHandler.prepareReturning("*", targetTableHandler.parseFieldFilter(targetTableRules?.insert?.returningFields));
1894
- let clientTargetInserts = insertedChildren.map(d => {
1895
- let _d = { ...d };
1896
- let res = {};
1897
- targetReturning.map(r => {
1898
- res[r.alias] = _d[r.alias];
1899
- });
1900
- return res;
1901
- });
1902
- returnData[targetTable] = clientTargetInserts.length === 1 ? clientTargetInserts[0] : clientTargetInserts;
1903
- }
1904
- }));
1905
- return returnData;
1906
- }
1907
- return row;
1908
- }));
1909
- let result = isMultiInsert ? _data : _data[0];
1910
- // if(validate && !isNestedInsert){
1911
- // result = isMultiInsert? await Promise.all(_data.map(async d => await validate({ ...d }))) : await validate({ ..._data[0] });
1912
- // }
1913
- let res = isNestedInsert ?
1914
- { insertResult: result } :
1915
- { data: result };
1916
- return res;
1917
- }
1918
1736
  async insert(rowOrRows, param2, param3_unused, tableRules, _localParams) {
1919
- const localParams = _localParams || {};
1920
- const { dbTX } = localParams;
1921
- try {
1922
- const { returning, onConflictDoNothing, fixIssues = false } = param2 || {};
1923
- const { testRule = false, returnQuery = false } = localParams || {};
1924
- let returningFields, forcedData, fields;
1925
- if (tableRules) {
1926
- if (!tableRules.insert)
1927
- throw "insert rules missing for " + this.name;
1928
- returningFields = tableRules.insert.returningFields;
1929
- forcedData = tableRules.insert.forcedData;
1930
- fields = tableRules.insert.fields;
1931
- /* If no returning fields specified then take select fields as returning */
1932
- if (!returningFields)
1933
- returningFields = (0, utils_1.get)(tableRules, "select.fields") || (0, utils_1.get)(tableRules, "insert.fields");
1934
- if (!fields)
1935
- throw ` invalid insert rule for ${this.name} -> fields missing `;
1936
- /* Safely test publish rules */
1937
- if (testRule) {
1938
- // if(this.is_media && tableRules.insert.preValidate) throw "Media table cannot have a preValidate. It already is used internally by prostgles for file upload";
1939
- await this.validateViewRules({ fields, returningFields, forcedFilter: forcedData, rule: "insert" });
1940
- if (forcedData) {
1941
- const keys = Object.keys(forcedData);
1942
- if (keys.length) {
1943
- try {
1944
- const colset = new exports.pgp.helpers.ColumnSet(this.columns.filter(c => keys.includes(c.name)).map(c => ({ name: c.name, cast: c.udt_name === "uuid" ? c.udt_name : undefined }))), values = exports.pgp.helpers.values(forcedData, colset), colNames = this.prepareSelect(keys, this.column_names);
1945
- await this.db.any("EXPLAIN INSERT INTO " + this.escapedName + " (${colNames:raw}) SELECT * FROM ( VALUES ${values:raw} ) t WHERE FALSE;", { colNames, values });
1946
- }
1947
- catch (e) {
1948
- throw "\nissue with forcedData: \nVALUE: " + JSON.stringify(forcedData, null, 2) + "\nERROR: " + e;
1949
- }
1950
- }
1951
- }
1952
- return true;
1953
- }
1954
- }
1955
- let conflict_query = "";
1956
- if (typeof onConflictDoNothing === "boolean" && onConflictDoNothing) {
1957
- conflict_query = " ON CONFLICT DO NOTHING ";
1958
- }
1959
- if (param2) {
1960
- const good_params = ["returning", "multi", "onConflictDoNothing", "fixIssues"];
1961
- const bad_params = Object.keys(param2).filter(k => !good_params.includes(k));
1962
- if (bad_params && bad_params.length)
1963
- throw "Invalid params: " + bad_params.join(", ") + " \n Expecting: " + good_params.join(", ");
1964
- }
1965
- if (!rowOrRows)
1966
- rowOrRows = {}; //throw "Provide data in param1";
1967
- let returningSelect = this.makeReturnQuery(await this.prepareReturning(returning, this.parseFieldFilter(returningFields)));
1968
- const makeQuery = async (_row, isOne = false) => {
1969
- let row = { ..._row };
1970
- if (!isPojoObject(row)) {
1971
- console.trace(row);
1972
- throw "\ninvalid insert data provided -> " + JSON.stringify(row);
1973
- }
1974
- const { data, allowedCols } = this.validateNewData({ row, forcedData, allowedFields: fields, tableRules, fixIssues });
1975
- let _data = { ...data };
1976
- let insertQ = "";
1977
- if (!Object.keys(_data).length)
1978
- insertQ = `INSERT INTO ${(0, prostgles_types_1.asName)(this.name)} DEFAULT VALUES `;
1979
- else
1980
- insertQ = await this.colSet.getInsertQuery(_data, allowedCols, tableRules?.insert?.validate); // pgp.helpers.insert(_data, columnSet);
1981
- return insertQ + conflict_query + returningSelect;
1982
- };
1983
- let query = "";
1984
- let queryType = "none";
1985
- /**
1986
- * If media it will: upload file and continue insert
1987
- * If nested insert it will: make separate inserts and not continue main insert
1988
- */
1989
- const insRes = await this.insertDataParse(rowOrRows, param2, param3_unused, tableRules, localParams);
1990
- const { data, insertResult } = insRes;
1991
- if ("insertResult" in insRes) {
1992
- return insertResult;
1993
- }
1994
- if (Array.isArray(data)) {
1995
- // if(returning) throw "Sorry but [returning] is dissalowed for multi insert";
1996
- let queries = await Promise.all(data.map(async (p) => {
1997
- const q = await makeQuery(p);
1998
- return q;
1999
- }));
2000
- query = exports.pgp.helpers.concat(queries);
2001
- if (returning)
2002
- queryType = "many";
2003
- }
2004
- else {
2005
- query = await makeQuery(data, true);
2006
- if (returning)
2007
- queryType = "one";
2008
- }
2009
- if (returnQuery)
2010
- return query;
2011
- let result;
2012
- if (this.dboBuilder.prostgles.opts.DEBUG_MODE) {
2013
- console.log(this.t?.ctx?.start, "insert in " + this.name, data);
2014
- }
2015
- const tx = dbTX?.[this.name]?.t || this.t;
2016
- const allowedFieldKeys = this.parseFieldFilter(fields);
2017
- if (tx) {
2018
- result = tx[queryType](query).catch((err) => makeErr(err, localParams, this, allowedFieldKeys));
2019
- }
2020
- else {
2021
- result = this.db.tx(t => t[queryType](query)).catch(err => makeErr(err, localParams, this, allowedFieldKeys));
2022
- }
2023
- return result;
2024
- }
2025
- catch (e) {
2026
- if (localParams && localParams.testRule)
2027
- throw e;
2028
- throw { err: parseError(e), msg: `Issue with dbo.${this.name}.insert(
2029
- ${JSON.stringify(rowOrRows || {}, null, 2)},
2030
- ${JSON.stringify(param2 || {}, null, 2)}
2031
- )` };
2032
- }
1737
+ return insert_1.insert.bind(this)(rowOrRows, param2, param3_unused, tableRules, _localParams);
2033
1738
  }
2034
- ;
2035
1739
  makeReturnQuery(items) {
2036
1740
  if (items?.length)
2037
1741
  return " RETURNING " + items.map(s => s.getQuery() + " AS " + (0, prostgles_types_1.asName)(s.alias)).join(", ");
@@ -2309,8 +2013,10 @@ class DboBuilder {
2309
2013
  async parseJoins() {
2310
2014
  if (this.prostgles.opts.joins) {
2311
2015
  let _joins = await this.prostgles.opts.joins;
2312
- let inferredJoins = await getInferredJoins(this.db, this.prostgles.opts.schema);
2313
- if (typeof _joins === "string" && _joins === "inferred") {
2016
+ if (!this.tablesOrViews)
2017
+ throw new Error("Could not create join config. this.tablesOrViews missing");
2018
+ let inferredJoins = await getInferredJoins2(this.tablesOrViews);
2019
+ if (_joins === "inferred") {
2314
2020
  _joins = inferredJoins;
2315
2021
  /* If joins are specified then include inferred joins except the explicit tables */
2316
2022
  }
@@ -2318,6 +2024,9 @@ class DboBuilder {
2318
2024
  const joinTables = _joins.map(j => j.tables).flat();
2319
2025
  _joins = _joins.concat(inferredJoins.filter(j => !j.tables.find(t => joinTables.includes(t))));
2320
2026
  }
2027
+ else if (_joins) {
2028
+ throw new Error("Unexpected joins init param. Expecting 'inferred' OR joinConfig but got: " + JSON.stringify(_joins));
2029
+ }
2321
2030
  let joins = JSON.parse(JSON.stringify(_joins));
2322
2031
  this.joins = joins;
2323
2032
  // Validate joins
@@ -3019,51 +2728,82 @@ function sqlErrCodeToMsg(code) {
3019
2728
  JSON.stringify([...THE_table_$0.rows].map(t => [...t.children].map(u => u.innerText)).filter((d, i) => i && d.length > 1).reduce((a, v)=>({ ...a, [v[0]]: v[1] }), {}))
3020
2729
  */
3021
2730
  }
3022
- async function getInferredJoins(db, schema = "public") {
2731
+ async function getInferredJoins2(schema) {
3023
2732
  let joins = [];
3024
- let res = await db.any(`SELECT
3025
- tc.table_schema,
3026
- tc.constraint_name,
3027
- tc.table_name,
3028
- kcu.column_name,
3029
- ccu.table_schema AS foreign_table_schema,
3030
- ccu.table_name AS foreign_table_name,
3031
- ccu.column_name AS foreign_column_name,
3032
- tc.constraint_type IN ('UNIQUE', 'PRIMARY KEY') as foreign_is_unique
3033
- FROM
3034
- information_schema.table_constraints AS tc
3035
- JOIN information_schema.key_column_usage AS kcu
3036
- ON tc.constraint_name = kcu.constraint_name
3037
- AND tc.table_schema = kcu.table_schema
3038
- JOIN information_schema.constraint_column_usage AS ccu
3039
- ON ccu.constraint_name = tc.constraint_name
3040
- AND ccu.table_schema = tc.table_schema
3041
- WHERE tc.table_schema=` + "${schema}" + `
3042
- AND tc.constraint_type = 'FOREIGN KEY'
3043
- AND tc.table_name <> ccu.table_name -- Exclude self-referencing tables
3044
- `, { schema });
3045
- res.map((d) => {
3046
- let eIdx = joins.findIndex(j => j.tables.includes(d.table_name) && j.tables.includes(d.foreign_table_name));
3047
- let existing = joins[eIdx];
2733
+ const upsertJoin = (t1, t2, cols) => {
2734
+ let existingIdx = joins.findIndex(j => j.tables.slice(0).sort().join() === [t1, t2].sort().join());
2735
+ let existing = joins[existingIdx];
2736
+ const normalCond = cols.reduce((a, v) => ({ ...a, [v.col1]: v.col2 }), {});
2737
+ const revertedCond = cols.reduce((a, v) => ({ ...a, [v.col2]: v.col1 }), {});
3048
2738
  if (existing) {
3049
- if (existing.tables[0] === d.table_name) {
3050
- existing.on = { ...existing.on, [d.column_name]: d.foreign_column_name };
3051
- }
3052
- else {
3053
- existing.on = { ...existing.on, [d.foreign_column_name]: d.column_name };
2739
+ const cond = existing.tables[0] === t1 ? normalCond : revertedCond;
2740
+ /** Avoid duplicates */
2741
+ if (!existing.on.some(_cond => JSON.stringify(_cond) === JSON.stringify(cond))) {
2742
+ existing.on.push(cond);
2743
+ joins[existingIdx] = existing;
3054
2744
  }
3055
- joins[eIdx] = existing;
3056
2745
  }
3057
2746
  else {
3058
2747
  joins.push({
3059
- tables: [d.table_name, d.foreign_table_name],
3060
- on: {
3061
- [d.column_name]: d.foreign_column_name
3062
- },
2748
+ tables: [t1, t2],
2749
+ on: [normalCond],
3063
2750
  type: "many-many"
3064
2751
  });
3065
2752
  }
2753
+ };
2754
+ schema.map(tov => {
2755
+ tov.columns.map(col => {
2756
+ if (col.references) {
2757
+ const r = col.references;
2758
+ upsertJoin(tov.name, r.ftable, r.cols.map((c, i) => ({ col1: c, col2: r.fcols[i] })));
2759
+ }
2760
+ });
3066
2761
  });
3067
2762
  return joins;
3068
2763
  }
2764
+ // async function getInferredJoins(db: DB, schema: string = "public"): Promise<Join[]>{
2765
+ // let joins: Join[] = [];
2766
+ // let res = await db.any(`SELECT
2767
+ // tc.table_schema,
2768
+ // tc.constraint_name,
2769
+ // tc.table_name,
2770
+ // kcu.column_name,
2771
+ // ccu.table_schema AS foreign_table_schema,
2772
+ // ccu.table_name AS foreign_table_name,
2773
+ // ccu.column_name AS foreign_column_name,
2774
+ // tc.constraint_type IN ('UNIQUE', 'PRIMARY KEY') as foreign_is_unique
2775
+ // FROM
2776
+ // information_schema.table_constraints AS tc
2777
+ // JOIN information_schema.key_column_usage AS kcu
2778
+ // ON tc.constraint_name = kcu.constraint_name
2779
+ // AND tc.table_schema = kcu.table_schema
2780
+ // JOIN information_schema.constraint_column_usage AS ccu
2781
+ // ON ccu.constraint_name = tc.constraint_name
2782
+ // AND ccu.table_schema = tc.table_schema
2783
+ // WHERE tc.table_schema=` + "${schema}" + `
2784
+ // AND tc.constraint_type = 'FOREIGN KEY'
2785
+ // AND tc.table_name <> ccu.table_name -- Exclude self-referencing tables
2786
+ // `, { schema });
2787
+ // res.map((d: any) => {
2788
+ // let eIdx = joins.findIndex(j => j.tables.includes(d.table_name) && j.tables.includes(d.foreign_table_name));
2789
+ // let existing = joins[eIdx];
2790
+ // if(existing){
2791
+ // if(existing.tables[0] === d.table_name){
2792
+ // existing.on = { ...existing.on, [d.column_name]: d.foreign_column_name }
2793
+ // } else {
2794
+ // existing.on = { ...existing.on, [d.foreign_column_name]: d.column_name }
2795
+ // }
2796
+ // joins[eIdx] = existing;
2797
+ // } else {
2798
+ // joins.push({
2799
+ // tables: [d.table_name, d.foreign_table_name],
2800
+ // on: {
2801
+ // [d.column_name]: d.foreign_column_name
2802
+ // },
2803
+ // type: "many-many"
2804
+ // })
2805
+ // }
2806
+ // });
2807
+ // return joins;
2808
+ // }
3069
2809
  //# sourceMappingURL=DboBuilder.js.map