@rebasepro/server-postgresql 0.0.1-canary.eae7889 → 0.1.0

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 (70) hide show
  1. package/dist/index.es.js +458 -201
  2. package/dist/index.es.js.map +1 -1
  3. package/dist/index.umd.js +458 -201
  4. package/dist/index.umd.js.map +1 -1
  5. package/dist/server-postgresql/src/PostgresBackendDriver.d.ts +8 -1
  6. package/dist/server-postgresql/src/schema/introspect-db-inference.d.ts +5 -0
  7. package/dist/server-postgresql/src/schema/introspect-db-logic.d.ts +117 -0
  8. package/dist/server-postgresql/src/schema/introspect-db.d.ts +1 -0
  9. package/dist/server-postgresql/src/services/EntityPersistService.d.ts +9 -0
  10. package/dist/types/src/controllers/auth.d.ts +8 -2
  11. package/dist/types/src/controllers/client.d.ts +13 -0
  12. package/dist/types/src/controllers/collection_registry.d.ts +2 -1
  13. package/dist/types/src/controllers/data_driver.d.ts +36 -1
  14. package/dist/types/src/controllers/navigation.d.ts +18 -6
  15. package/dist/types/src/controllers/registry.d.ts +9 -1
  16. package/dist/types/src/controllers/side_entity_controller.d.ts +7 -0
  17. package/dist/types/src/rebase_context.d.ts +17 -0
  18. package/dist/types/src/types/backend_hooks.d.ts +187 -0
  19. package/dist/types/src/types/collections.d.ts +31 -11
  20. package/dist/types/src/types/component_ref.d.ts +47 -0
  21. package/dist/types/src/types/cron.d.ts +1 -1
  22. package/dist/types/src/types/entity_views.d.ts +6 -7
  23. package/dist/types/src/types/formex.d.ts +40 -0
  24. package/dist/types/src/types/index.d.ts +3 -0
  25. package/dist/types/src/types/plugins.d.ts +6 -3
  26. package/dist/types/src/types/properties.d.ts +72 -88
  27. package/dist/types/src/types/slots.d.ts +20 -10
  28. package/dist/types/src/types/translations.d.ts +6 -0
  29. package/examples/sdk-demo/node_modules/esbuild/LICENSE.md +21 -0
  30. package/examples/sdk-demo/node_modules/esbuild/README.md +3 -0
  31. package/examples/sdk-demo/node_modules/esbuild/bin/esbuild +223 -0
  32. package/examples/sdk-demo/node_modules/esbuild/install.js +289 -0
  33. package/examples/sdk-demo/node_modules/esbuild/lib/main.d.ts +716 -0
  34. package/examples/sdk-demo/node_modules/esbuild/lib/main.js +2242 -0
  35. package/examples/sdk-demo/node_modules/esbuild/package.json +49 -0
  36. package/package.json +6 -5
  37. package/src/PostgresBackendDriver.ts +32 -6
  38. package/src/cli.ts +68 -2
  39. package/src/data-transformer.ts +84 -1
  40. package/src/schema/doctor.ts +14 -2
  41. package/src/schema/generate-drizzle-schema-logic.ts +59 -30
  42. package/src/schema/introspect-db-inference.ts +238 -0
  43. package/src/schema/introspect-db-logic.ts +896 -0
  44. package/src/schema/introspect-db.ts +254 -0
  45. package/src/services/EntityFetchService.ts +16 -0
  46. package/src/services/EntityPersistService.ts +95 -13
  47. package/test/generate-drizzle-schema.test.ts +342 -0
  48. package/test/introspect-db-generation.test.ts +458 -0
  49. package/test/introspect-db-utils.test.ts +392 -0
  50. package/test/property-ordering.test.ts +395 -0
  51. package/test/relations.test.ts +4 -4
  52. package/test/unmapped-tables-safety.test.ts +345 -0
  53. package/jest-all.log +0 -3128
  54. package/jest.log +0 -49
  55. package/scratch.ts +0 -41
  56. package/test-drizzle-bug.ts +0 -18
  57. package/test-drizzle-out/0000_cultured_freak.sql +0 -7
  58. package/test-drizzle-out/0001_tiresome_professor_monster.sql +0 -1
  59. package/test-drizzle-out/meta/0000_snapshot.json +0 -55
  60. package/test-drizzle-out/meta/0001_snapshot.json +0 -63
  61. package/test-drizzle-out/meta/_journal.json +0 -20
  62. package/test-drizzle-prompt.sh +0 -2
  63. package/test-policy-prompt.sh +0 -3
  64. package/test-programmatic.ts +0 -30
  65. package/test-programmatic2.ts +0 -59
  66. package/test-schema-no-policies.ts +0 -12
  67. package/test_drizzle_mock.js +0 -3
  68. package/test_find_changed.mjs +0 -32
  69. package/test_hash.js +0 -14
  70. package/test_output.txt +0 -3145
package/dist/index.umd.js CHANGED
@@ -132,7 +132,8 @@
132
132
  }
133
133
  const DEFAULT_ONE_OF_TYPE = "type";
134
134
  const DEFAULT_ONE_OF_VALUE = "value";
135
- const snakeCaseRegex = /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g;
135
+ const tokenizeRegex = /[A-Z]{2,}(?=[A-Z][a-z]|\b)|[A-Z]?[a-z]+|[0-9]+(?:[a-z](?![a-z]))?|[A-Z]/g;
136
+ const snakeCaseRegex = tokenizeRegex;
136
137
  const toSnakeCase = (str) => {
137
138
  const regExpMatchArray = str.match(snakeCaseRegex);
138
139
  if (!regExpMatchArray) return "";
@@ -1029,6 +1030,80 @@
1029
1030
  const singularName = snakeCaseName.endsWith("s") ? snakeCaseName.slice(0, -1) : snakeCaseName;
1030
1031
  return `${singularName}_id`;
1031
1032
  }
1033
+ function updateDateAutoValues({
1034
+ inputValues,
1035
+ properties,
1036
+ status,
1037
+ timestampNowValue
1038
+ }) {
1039
+ return traverseValuesProperties(inputValues, properties, (inputValue, property) => {
1040
+ if (property.type === "date") {
1041
+ if (status === "existing" && property.autoValue === "on_update") {
1042
+ return timestampNowValue;
1043
+ } else if ((status === "new" || status === "copy") && (property.autoValue === "on_update" || property.autoValue === "on_create")) {
1044
+ return timestampNowValue;
1045
+ } else {
1046
+ return inputValue;
1047
+ }
1048
+ } else {
1049
+ return inputValue;
1050
+ }
1051
+ }) ?? {};
1052
+ }
1053
+ function traverseValuesProperties(inputValues, properties, operation) {
1054
+ const safeInputValues = inputValues ?? {};
1055
+ const updatedValues = Object.entries(properties).map(([key, property]) => {
1056
+ const inputValue = safeInputValues && safeInputValues[key];
1057
+ const updatedValue = traverseValueProperty(inputValue, property, operation);
1058
+ if (updatedValue === null) return null;
1059
+ if (updatedValue === void 0) return void 0;
1060
+ return {
1061
+ [key]: updatedValue
1062
+ };
1063
+ }).reduce((a, b) => ({
1064
+ ...a,
1065
+ ...b
1066
+ }), {});
1067
+ const result = mergeDeep(safeInputValues, updatedValues);
1068
+ if (!result || Object.keys(result).length === 0) return void 0;
1069
+ return result;
1070
+ }
1071
+ function traverseValueProperty(inputValue, property, operation) {
1072
+ let value;
1073
+ if (property.type === "map" && property.properties) {
1074
+ value = traverseValuesProperties(inputValue, property.properties, operation);
1075
+ } else if (property.type === "array") {
1076
+ const of = property.of;
1077
+ if (of && Array.isArray(inputValue) && !Array.isArray(of)) {
1078
+ value = inputValue.map((e) => traverseValueProperty(e, of, operation));
1079
+ } else if (of && Array.isArray(inputValue) && Array.isArray(of)) {
1080
+ value = inputValue.map((e, i) => {
1081
+ if (i < of.length) return traverseValueProperty(e, of[i], operation);
1082
+ return null;
1083
+ }).filter(Boolean);
1084
+ } else if (property.oneOf && Array.isArray(inputValue)) {
1085
+ const typeField = property.oneOf?.typeField ?? DEFAULT_ONE_OF_TYPE;
1086
+ const valueField = property.oneOf?.valueField ?? DEFAULT_ONE_OF_VALUE;
1087
+ value = inputValue.map((e) => {
1088
+ if (e === null) return null;
1089
+ if (typeof e !== "object") return e;
1090
+ const rec = e;
1091
+ const type = rec[typeField];
1092
+ const childProperty = property.oneOf?.properties[type];
1093
+ if (!type || !childProperty) return e;
1094
+ return {
1095
+ [typeField]: type,
1096
+ [valueField]: traverseValueProperty(rec[valueField], childProperty, operation)
1097
+ };
1098
+ });
1099
+ } else {
1100
+ value = inputValue;
1101
+ }
1102
+ } else {
1103
+ value = operation(inputValue, property);
1104
+ }
1105
+ return value;
1106
+ }
1032
1107
  function createRelationRef(id, path2) {
1033
1108
  return {
1034
1109
  id,
@@ -1725,8 +1800,8 @@
1725
1800
  return jsonLogic;
1726
1801
  });
1727
1802
  })(logic);
1728
- var getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols;
1729
- var hasOwnProperty$a = Object.prototype.hasOwnProperty;
1803
+ const { getOwnPropertyNames, getOwnPropertySymbols } = Object;
1804
+ const { hasOwnProperty: hasOwnProperty$a } = Object.prototype;
1730
1805
  function combineComparators(comparatorA, comparatorB) {
1731
1806
  return function isEqual(a, b, state) {
1732
1807
  return comparatorA(a, b, state) && comparatorB(a, b, state);
@@ -1737,38 +1812,45 @@
1737
1812
  if (!a || !b || typeof a !== "object" || typeof b !== "object") {
1738
1813
  return areItemsEqual(a, b, state);
1739
1814
  }
1740
- var cache = state.cache;
1741
- var cachedA = cache.get(a);
1742
- var cachedB = cache.get(b);
1815
+ const { cache } = state;
1816
+ const cachedA = cache.get(a);
1817
+ const cachedB = cache.get(b);
1743
1818
  if (cachedA && cachedB) {
1744
1819
  return cachedA === b && cachedB === a;
1745
1820
  }
1746
1821
  cache.set(a, b);
1747
1822
  cache.set(b, a);
1748
- var result = areItemsEqual(a, b, state);
1823
+ const result = areItemsEqual(a, b, state);
1749
1824
  cache.delete(a);
1750
1825
  cache.delete(b);
1751
1826
  return result;
1752
1827
  };
1753
1828
  }
1754
- function getShortTag(value) {
1755
- return value != null ? value[Symbol.toStringTag] : void 0;
1756
- }
1757
1829
  function getStrictProperties(object) {
1758
1830
  return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
1759
1831
  }
1760
- var hasOwn = Object.hasOwn || function(object, property) {
1761
- return hasOwnProperty$a.call(object, property);
1762
- };
1763
- function sameValueZeroEqual(a, b) {
1764
- return a === b || !a && !b && a !== a && b !== b;
1832
+ const hasOwn = (
1833
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1834
+ Object.hasOwn || ((object, property) => hasOwnProperty$a.call(object, property))
1835
+ );
1836
+ const PREACT_VNODE = "__v";
1837
+ const PREACT_OWNER = "__o";
1838
+ const REACT_OWNER = "_owner";
1839
+ const { getOwnPropertyDescriptor, keys: keys$4 } = Object;
1840
+ const sameValueEqual = (
1841
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1842
+ Object.is || function sameValueEqual2(a, b) {
1843
+ return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b;
1844
+ }
1845
+ );
1846
+ function strictEqual(a, b) {
1847
+ return a === b;
1848
+ }
1849
+ function areArrayBuffersEqual(a, b) {
1850
+ return a.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a), new Uint8Array(b));
1765
1851
  }
1766
- var PREACT_VNODE = "__v";
1767
- var PREACT_OWNER = "__o";
1768
- var REACT_OWNER = "_owner";
1769
- var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, keys$4 = Object.keys;
1770
1852
  function areArraysEqual(a, b, state) {
1771
- var index = a.length;
1853
+ let index = a.length;
1772
1854
  if (b.length !== index) {
1773
1855
  return false;
1774
1856
  }
@@ -1779,35 +1861,35 @@
1779
1861
  }
1780
1862
  return true;
1781
1863
  }
1864
+ function areDataViewsEqual(a, b) {
1865
+ return a.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength));
1866
+ }
1782
1867
  function areDatesEqual(a, b) {
1783
- return sameValueZeroEqual(a.getTime(), b.getTime());
1868
+ return sameValueEqual(a.getTime(), b.getTime());
1784
1869
  }
1785
1870
  function areErrorsEqual(a, b) {
1786
1871
  return a.name === b.name && a.message === b.message && a.cause === b.cause && a.stack === b.stack;
1787
1872
  }
1788
- function areFunctionsEqual(a, b) {
1789
- return a === b;
1790
- }
1791
1873
  function areMapsEqual(a, b, state) {
1792
- var size = a.size;
1874
+ const size = a.size;
1793
1875
  if (size !== b.size) {
1794
1876
  return false;
1795
1877
  }
1796
1878
  if (!size) {
1797
1879
  return true;
1798
1880
  }
1799
- var matchedIndices = new Array(size);
1800
- var aIterable = a.entries();
1801
- var aResult;
1802
- var bResult;
1803
- var index = 0;
1881
+ const matchedIndices = new Array(size);
1882
+ const aIterable = a.entries();
1883
+ let aResult;
1884
+ let bResult;
1885
+ let index = 0;
1804
1886
  while (aResult = aIterable.next()) {
1805
1887
  if (aResult.done) {
1806
1888
  break;
1807
1889
  }
1808
- var bIterable = b.entries();
1809
- var hasMatch = false;
1810
- var matchIndex = 0;
1890
+ const bIterable = b.entries();
1891
+ let hasMatch = false;
1892
+ let matchIndex = 0;
1811
1893
  while (bResult = bIterable.next()) {
1812
1894
  if (bResult.done) {
1813
1895
  break;
@@ -1816,8 +1898,8 @@
1816
1898
  matchIndex++;
1817
1899
  continue;
1818
1900
  }
1819
- var aEntry = aResult.value;
1820
- var bEntry = bResult.value;
1901
+ const aEntry = aResult.value;
1902
+ const bEntry = bResult.value;
1821
1903
  if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a, b, state) && state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a, b, state)) {
1822
1904
  hasMatch = matchedIndices[matchIndex] = true;
1823
1905
  break;
@@ -1831,10 +1913,9 @@
1831
1913
  }
1832
1914
  return true;
1833
1915
  }
1834
- var areNumbersEqual = sameValueZeroEqual;
1835
1916
  function areObjectsEqual(a, b, state) {
1836
- var properties = keys$4(a);
1837
- var index = properties.length;
1917
+ const properties = keys$4(a);
1918
+ let index = properties.length;
1838
1919
  if (keys$4(b).length !== index) {
1839
1920
  return false;
1840
1921
  }
@@ -1846,14 +1927,14 @@
1846
1927
  return true;
1847
1928
  }
1848
1929
  function areObjectsEqualStrict(a, b, state) {
1849
- var properties = getStrictProperties(a);
1850
- var index = properties.length;
1930
+ const properties = getStrictProperties(a);
1931
+ let index = properties.length;
1851
1932
  if (getStrictProperties(b).length !== index) {
1852
1933
  return false;
1853
1934
  }
1854
- var property;
1855
- var descriptorA;
1856
- var descriptorB;
1935
+ let property;
1936
+ let descriptorA;
1937
+ let descriptorB;
1857
1938
  while (index-- > 0) {
1858
1939
  property = properties[index];
1859
1940
  if (!isPropertyEqual(a, b, state, property)) {
@@ -1868,30 +1949,30 @@
1868
1949
  return true;
1869
1950
  }
1870
1951
  function arePrimitiveWrappersEqual(a, b) {
1871
- return sameValueZeroEqual(a.valueOf(), b.valueOf());
1952
+ return sameValueEqual(a.valueOf(), b.valueOf());
1872
1953
  }
1873
1954
  function areRegExpsEqual(a, b) {
1874
1955
  return a.source === b.source && a.flags === b.flags;
1875
1956
  }
1876
1957
  function areSetsEqual(a, b, state) {
1877
- var size = a.size;
1958
+ const size = a.size;
1878
1959
  if (size !== b.size) {
1879
1960
  return false;
1880
1961
  }
1881
1962
  if (!size) {
1882
1963
  return true;
1883
1964
  }
1884
- var matchedIndices = new Array(size);
1885
- var aIterable = a.values();
1886
- var aResult;
1887
- var bResult;
1965
+ const matchedIndices = new Array(size);
1966
+ const aIterable = a.values();
1967
+ let aResult;
1968
+ let bResult;
1888
1969
  while (aResult = aIterable.next()) {
1889
1970
  if (aResult.done) {
1890
1971
  break;
1891
1972
  }
1892
- var bIterable = b.values();
1893
- var hasMatch = false;
1894
- var matchIndex = 0;
1973
+ const bIterable = b.values();
1974
+ let hasMatch = false;
1975
+ let matchIndex = 0;
1895
1976
  while (bResult = bIterable.next()) {
1896
1977
  if (bResult.done) {
1897
1978
  break;
@@ -1909,8 +1990,8 @@
1909
1990
  return true;
1910
1991
  }
1911
1992
  function areTypedArraysEqual(a, b) {
1912
- var index = a.length;
1913
- if (b.length !== index) {
1993
+ let index = a.byteLength;
1994
+ if (b.byteLength !== index || a.byteOffset !== b.byteOffset) {
1914
1995
  return false;
1915
1996
  }
1916
1997
  while (index-- > 0) {
@@ -1929,23 +2010,10 @@
1929
2010
  }
1930
2011
  return hasOwn(b, property) && state.equals(a[property], b[property], property, property, a, b, state);
1931
2012
  }
1932
- var ARGUMENTS_TAG = "[object Arguments]";
1933
- var BOOLEAN_TAG = "[object Boolean]";
1934
- var DATE_TAG = "[object Date]";
1935
- var ERROR_TAG = "[object Error]";
1936
- var MAP_TAG = "[object Map]";
1937
- var NUMBER_TAG = "[object Number]";
1938
- var OBJECT_TAG = "[object Object]";
1939
- var REG_EXP_TAG = "[object RegExp]";
1940
- var SET_TAG = "[object Set]";
1941
- var STRING_TAG = "[object String]";
1942
- var URL_TAG = "[object URL]";
1943
- var isArray$4 = Array.isArray;
1944
- var isTypedArray$2 = typeof ArrayBuffer === "function" && ArrayBuffer.isView ? ArrayBuffer.isView : null;
1945
- var assign = Object.assign;
1946
- var getTag$4 = Object.prototype.toString.call.bind(Object.prototype.toString);
1947
- function createEqualityComparator(_a) {
1948
- var areArraysEqual2 = _a.areArraysEqual, areDatesEqual2 = _a.areDatesEqual, areErrorsEqual2 = _a.areErrorsEqual, areFunctionsEqual2 = _a.areFunctionsEqual, areMapsEqual2 = _a.areMapsEqual, areNumbersEqual2 = _a.areNumbersEqual, areObjectsEqual2 = _a.areObjectsEqual, arePrimitiveWrappersEqual2 = _a.arePrimitiveWrappersEqual, areRegExpsEqual2 = _a.areRegExpsEqual, areSetsEqual2 = _a.areSetsEqual, areTypedArraysEqual2 = _a.areTypedArraysEqual, areUrlsEqual2 = _a.areUrlsEqual, unknownTagComparators = _a.unknownTagComparators;
2013
+ const toString = Object.prototype.toString;
2014
+ function createEqualityComparator(config) {
2015
+ const supportedComparatorMap = createSupportedComparatorMap(config);
2016
+ const { areArraysEqual: areArraysEqual2, areDatesEqual: areDatesEqual2, areFunctionsEqual, areMapsEqual: areMapsEqual2, areNumbersEqual, areObjectsEqual: areObjectsEqual2, areRegExpsEqual: areRegExpsEqual2, areSetsEqual: areSetsEqual2, getUnsupportedCustomComparator } = config;
1949
2017
  return function comparator(a, b, state) {
1950
2018
  if (a === b) {
1951
2019
  return true;
@@ -1953,32 +2021,29 @@
1953
2021
  if (a == null || b == null) {
1954
2022
  return false;
1955
2023
  }
1956
- var type = typeof a;
2024
+ const type = typeof a;
1957
2025
  if (type !== typeof b) {
1958
2026
  return false;
1959
2027
  }
1960
2028
  if (type !== "object") {
1961
- if (type === "number") {
1962
- return areNumbersEqual2(a, b, state);
2029
+ if (type === "number" || type === "bigint") {
2030
+ return areNumbersEqual(a, b, state);
1963
2031
  }
1964
2032
  if (type === "function") {
1965
- return areFunctionsEqual2(a, b, state);
2033
+ return areFunctionsEqual(a, b, state);
1966
2034
  }
1967
2035
  return false;
1968
2036
  }
1969
- var constructor = a.constructor;
2037
+ const constructor = a.constructor;
1970
2038
  if (constructor !== b.constructor) {
1971
2039
  return false;
1972
2040
  }
1973
2041
  if (constructor === Object) {
1974
2042
  return areObjectsEqual2(a, b, state);
1975
2043
  }
1976
- if (isArray$4(a)) {
2044
+ if (constructor === Array) {
1977
2045
  return areArraysEqual2(a, b, state);
1978
2046
  }
1979
- if (isTypedArray$2 != null && isTypedArray$2(a)) {
1980
- return areTypedArraysEqual2(a, b, state);
1981
- }
1982
2047
  if (constructor === Date) {
1983
2048
  return areDatesEqual2(a, b, state);
1984
2049
  }
@@ -1991,79 +2056,55 @@
1991
2056
  if (constructor === Set) {
1992
2057
  return areSetsEqual2(a, b, state);
1993
2058
  }
1994
- var tag = getTag$4(a);
1995
- if (tag === DATE_TAG) {
1996
- return areDatesEqual2(a, b, state);
1997
- }
1998
- if (tag === REG_EXP_TAG) {
1999
- return areRegExpsEqual2(a, b, state);
2000
- }
2001
- if (tag === MAP_TAG) {
2002
- return areMapsEqual2(a, b, state);
2003
- }
2004
- if (tag === SET_TAG) {
2005
- return areSetsEqual2(a, b, state);
2006
- }
2007
- if (tag === OBJECT_TAG) {
2008
- return typeof a.then !== "function" && typeof b.then !== "function" && areObjectsEqual2(a, b, state);
2059
+ if (constructor === Promise) {
2060
+ return false;
2009
2061
  }
2010
- if (tag === URL_TAG) {
2011
- return areUrlsEqual2(a, b, state);
2062
+ if (Array.isArray(a)) {
2063
+ return areArraysEqual2(a, b, state);
2012
2064
  }
2013
- if (tag === ERROR_TAG) {
2014
- return areErrorsEqual2(a, b, state);
2065
+ const tag = toString.call(a);
2066
+ const supportedComparator = supportedComparatorMap[tag];
2067
+ if (supportedComparator) {
2068
+ return supportedComparator(a, b, state);
2015
2069
  }
2016
- if (tag === ARGUMENTS_TAG) {
2017
- return areObjectsEqual2(a, b, state);
2018
- }
2019
- if (tag === BOOLEAN_TAG || tag === NUMBER_TAG || tag === STRING_TAG) {
2020
- return arePrimitiveWrappersEqual2(a, b, state);
2021
- }
2022
- if (unknownTagComparators) {
2023
- var unknownTagComparator = unknownTagComparators[tag];
2024
- if (!unknownTagComparator) {
2025
- var shortTag = getShortTag(a);
2026
- if (shortTag) {
2027
- unknownTagComparator = unknownTagComparators[shortTag];
2028
- }
2029
- }
2030
- if (unknownTagComparator) {
2031
- return unknownTagComparator(a, b, state);
2032
- }
2070
+ const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, state, tag);
2071
+ if (unsupportedCustomComparator) {
2072
+ return unsupportedCustomComparator(a, b, state);
2033
2073
  }
2034
2074
  return false;
2035
2075
  };
2036
2076
  }
2037
- function createEqualityComparatorConfig(_a) {
2038
- var circular = _a.circular, createCustomConfig = _a.createCustomConfig, strict = _a.strict;
2039
- var config = {
2077
+ function createEqualityComparatorConfig({ circular, createCustomConfig, strict }) {
2078
+ let config = {
2079
+ areArrayBuffersEqual,
2040
2080
  areArraysEqual: strict ? areObjectsEqualStrict : areArraysEqual,
2081
+ areDataViewsEqual,
2041
2082
  areDatesEqual,
2042
2083
  areErrorsEqual,
2043
- areFunctionsEqual,
2084
+ areFunctionsEqual: strictEqual,
2044
2085
  areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
2045
- areNumbersEqual,
2086
+ areNumbersEqual: sameValueEqual,
2046
2087
  areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
2047
2088
  arePrimitiveWrappersEqual,
2048
2089
  areRegExpsEqual,
2049
2090
  areSetsEqual: strict ? combineComparators(areSetsEqual, areObjectsEqualStrict) : areSetsEqual,
2050
- areTypedArraysEqual: strict ? areObjectsEqualStrict : areTypedArraysEqual,
2091
+ areTypedArraysEqual: strict ? combineComparators(areTypedArraysEqual, areObjectsEqualStrict) : areTypedArraysEqual,
2051
2092
  areUrlsEqual,
2052
- unknownTagComparators: void 0
2093
+ getUnsupportedCustomComparator: void 0
2053
2094
  };
2054
2095
  if (createCustomConfig) {
2055
- config = assign({}, config, createCustomConfig(config));
2096
+ config = Object.assign({}, config, createCustomConfig(config));
2056
2097
  }
2057
2098
  if (circular) {
2058
- var areArraysEqual$1 = createIsCircular(config.areArraysEqual);
2059
- var areMapsEqual$1 = createIsCircular(config.areMapsEqual);
2060
- var areObjectsEqual$1 = createIsCircular(config.areObjectsEqual);
2061
- var areSetsEqual$1 = createIsCircular(config.areSetsEqual);
2062
- config = assign({}, config, {
2063
- areArraysEqual: areArraysEqual$1,
2064
- areMapsEqual: areMapsEqual$1,
2065
- areObjectsEqual: areObjectsEqual$1,
2066
- areSetsEqual: areSetsEqual$1
2099
+ const areArraysEqual2 = createIsCircular(config.areArraysEqual);
2100
+ const areMapsEqual2 = createIsCircular(config.areMapsEqual);
2101
+ const areObjectsEqual2 = createIsCircular(config.areObjectsEqual);
2102
+ const areSetsEqual2 = createIsCircular(config.areSetsEqual);
2103
+ config = Object.assign({}, config, {
2104
+ areArraysEqual: areArraysEqual2,
2105
+ areMapsEqual: areMapsEqual2,
2106
+ areObjectsEqual: areObjectsEqual2,
2107
+ areSetsEqual: areSetsEqual2
2067
2108
  });
2068
2109
  }
2069
2110
  return config;
@@ -2073,11 +2114,10 @@
2073
2114
  return compare(a, b, state);
2074
2115
  };
2075
2116
  }
2076
- function createIsEqual(_a) {
2077
- var circular = _a.circular, comparator = _a.comparator, createState = _a.createState, equals = _a.equals, strict = _a.strict;
2117
+ function createIsEqual({ circular, comparator, createState, equals, strict }) {
2078
2118
  if (createState) {
2079
2119
  return function isEqual(a, b) {
2080
- var _a2 = createState(), _b = _a2.cache, cache = _b === void 0 ? circular ? /* @__PURE__ */ new WeakMap() : void 0 : _b, meta = _a2.meta;
2120
+ const { cache = circular ? /* @__PURE__ */ new WeakMap() : void 0, meta } = createState();
2081
2121
  return comparator(a, b, {
2082
2122
  cache,
2083
2123
  equals,
@@ -2096,7 +2136,7 @@
2096
2136
  });
2097
2137
  };
2098
2138
  }
2099
- var state = {
2139
+ const state = {
2100
2140
  cache: void 0,
2101
2141
  equals,
2102
2142
  meta: void 0,
@@ -2106,7 +2146,50 @@
2106
2146
  return comparator(a, b, state);
2107
2147
  };
2108
2148
  }
2109
- var deepEqual = createCustomEqual();
2149
+ function createSupportedComparatorMap({ areArrayBuffersEqual: areArrayBuffersEqual2, areArraysEqual: areArraysEqual2, areDataViewsEqual: areDataViewsEqual2, areDatesEqual: areDatesEqual2, areErrorsEqual: areErrorsEqual2, areFunctionsEqual, areMapsEqual: areMapsEqual2, areNumbersEqual, areObjectsEqual: areObjectsEqual2, arePrimitiveWrappersEqual: arePrimitiveWrappersEqual2, areRegExpsEqual: areRegExpsEqual2, areSetsEqual: areSetsEqual2, areTypedArraysEqual: areTypedArraysEqual2, areUrlsEqual: areUrlsEqual2 }) {
2150
+ return {
2151
+ "[object Arguments]": areObjectsEqual2,
2152
+ "[object Array]": areArraysEqual2,
2153
+ "[object ArrayBuffer]": areArrayBuffersEqual2,
2154
+ "[object AsyncGeneratorFunction]": areFunctionsEqual,
2155
+ "[object BigInt]": areNumbersEqual,
2156
+ "[object BigInt64Array]": areTypedArraysEqual2,
2157
+ "[object BigUint64Array]": areTypedArraysEqual2,
2158
+ "[object Boolean]": arePrimitiveWrappersEqual2,
2159
+ "[object DataView]": areDataViewsEqual2,
2160
+ "[object Date]": areDatesEqual2,
2161
+ // If an error tag, it should be tested explicitly. Like RegExp, the properties are not
2162
+ // enumerable, and therefore will give false positives if tested like a standard object.
2163
+ "[object Error]": areErrorsEqual2,
2164
+ "[object Float16Array]": areTypedArraysEqual2,
2165
+ "[object Float32Array]": areTypedArraysEqual2,
2166
+ "[object Float64Array]": areTypedArraysEqual2,
2167
+ "[object Function]": areFunctionsEqual,
2168
+ "[object GeneratorFunction]": areFunctionsEqual,
2169
+ "[object Int8Array]": areTypedArraysEqual2,
2170
+ "[object Int16Array]": areTypedArraysEqual2,
2171
+ "[object Int32Array]": areTypedArraysEqual2,
2172
+ "[object Map]": areMapsEqual2,
2173
+ "[object Number]": arePrimitiveWrappersEqual2,
2174
+ "[object Object]": (a, b, state) => (
2175
+ // The exception for value comparison is custom `Promise`-like class instances. These should
2176
+ // be treated the same as standard `Promise` objects, which means strict equality, and if
2177
+ // it reaches this point then that strict equality comparison has already failed.
2178
+ typeof a.then !== "function" && typeof b.then !== "function" && areObjectsEqual2(a, b, state)
2179
+ ),
2180
+ // For RegExp, the properties are not enumerable, and therefore will give false positives if
2181
+ // tested like a standard object.
2182
+ "[object RegExp]": areRegExpsEqual2,
2183
+ "[object Set]": areSetsEqual2,
2184
+ "[object String]": arePrimitiveWrappersEqual2,
2185
+ "[object URL]": areUrlsEqual2,
2186
+ "[object Uint8Array]": areTypedArraysEqual2,
2187
+ "[object Uint8ClampedArray]": areTypedArraysEqual2,
2188
+ "[object Uint16Array]": areTypedArraysEqual2,
2189
+ "[object Uint32Array]": areTypedArraysEqual2
2190
+ };
2191
+ }
2192
+ const deepEqual = createCustomEqual();
2110
2193
  createCustomEqual({ strict: true });
2111
2194
  createCustomEqual({ circular: true });
2112
2195
  createCustomEqual({
@@ -2114,37 +2197,26 @@
2114
2197
  strict: true
2115
2198
  });
2116
2199
  createCustomEqual({
2117
- createInternalComparator: function() {
2118
- return sameValueZeroEqual;
2119
- }
2200
+ createInternalComparator: () => sameValueEqual
2120
2201
  });
2121
2202
  createCustomEqual({
2122
2203
  strict: true,
2123
- createInternalComparator: function() {
2124
- return sameValueZeroEqual;
2125
- }
2204
+ createInternalComparator: () => sameValueEqual
2126
2205
  });
2127
2206
  createCustomEqual({
2128
2207
  circular: true,
2129
- createInternalComparator: function() {
2130
- return sameValueZeroEqual;
2131
- }
2208
+ createInternalComparator: () => sameValueEqual
2132
2209
  });
2133
2210
  createCustomEqual({
2134
2211
  circular: true,
2135
- createInternalComparator: function() {
2136
- return sameValueZeroEqual;
2137
- },
2212
+ createInternalComparator: () => sameValueEqual,
2138
2213
  strict: true
2139
2214
  });
2140
- function createCustomEqual(options) {
2141
- if (options === void 0) {
2142
- options = {};
2143
- }
2144
- var _a = options.circular, circular = _a === void 0 ? false : _a, createCustomInternalComparator = options.createInternalComparator, createState = options.createState, _b = options.strict, strict = _b === void 0 ? false : _b;
2145
- var config = createEqualityComparatorConfig(options);
2146
- var comparator = createEqualityComparator(config);
2147
- var equals = createCustomInternalComparator ? createCustomInternalComparator(comparator) : createInternalEqualityComparator(comparator);
2215
+ function createCustomEqual(options = {}) {
2216
+ const { circular = false, createInternalComparator: createCustomInternalComparator, createState, strict = false } = options;
2217
+ const config = createEqualityComparatorConfig(options);
2218
+ const comparator = createEqualityComparator(config);
2219
+ const equals = createCustomInternalComparator ? createCustomInternalComparator(comparator) : createInternalEqualityComparator(comparator);
2148
2220
  return createIsEqual({ circular, comparator, createState, equals, strict });
2149
2221
  }
2150
2222
  function listCacheClear$1() {
@@ -2619,8 +2691,8 @@
2619
2691
  var freeExports = exports$1 && !exports$1.nodeType && exports$1;
2620
2692
  var freeModule = freeExports && true && module2 && !module2.nodeType && module2;
2621
2693
  var moduleExports = freeModule && freeModule.exports === freeExports;
2622
- var Buffer = moduleExports ? root2.Buffer : void 0;
2623
- var nativeIsBuffer = Buffer ? Buffer.isBuffer : void 0;
2694
+ var Buffer2 = moduleExports ? root2.Buffer : void 0;
2695
+ var nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : void 0;
2624
2696
  var isBuffer2 = nativeIsBuffer || stubFalse2;
2625
2697
  module2.exports = isBuffer2;
2626
2698
  })(isBuffer$2, isBuffer$2.exports);
@@ -2785,7 +2857,7 @@
2785
2857
  var freeExports = exports$1 && !exports$1.nodeType && exports$1;
2786
2858
  var freeModule = freeExports && true && module2 && !module2.nodeType && module2;
2787
2859
  var moduleExports = freeModule && freeModule.exports === freeExports;
2788
- var Buffer = moduleExports ? root2.Buffer : void 0, allocUnsafe = Buffer ? Buffer.allocUnsafe : void 0;
2860
+ var Buffer2 = moduleExports ? root2.Buffer : void 0, allocUnsafe = Buffer2 ? Buffer2.allocUnsafe : void 0;
2789
2861
  function cloneBuffer2(buffer, isDeep) {
2790
2862
  if (isDeep) {
2791
2863
  return buffer.slice();
@@ -3394,7 +3466,10 @@
3394
3466
  if (!relation) {
3395
3467
  throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'`);
3396
3468
  }
3397
- currentCollection = relation.target();
3469
+ const target = relation.target();
3470
+ const targetRelationKey = relation.relationName || target.slug;
3471
+ const targetSlug = relation.overrides?.slug ?? targetRelationKey;
3472
+ currentCollection = this.get(targetSlug) || this.normalizeCollection(target);
3398
3473
  if (i + 1 < pathSegments.length) ;
3399
3474
  }
3400
3475
  return currentCollection;
@@ -3443,7 +3518,7 @@
3443
3518
  if (!subcollection) {
3444
3519
  throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
3445
3520
  }
3446
- currentCollection = subcollection;
3521
+ currentCollection = this.get(subcollection.slug) || this.normalizeCollection(subcollection);
3447
3522
  collections.push(currentCollection);
3448
3523
  }
3449
3524
  }
@@ -4485,7 +4560,25 @@
4485
4560
  return result;
4486
4561
  }
4487
4562
  return value;
4563
+ case "string":
4564
+ if (typeof value === "string") {
4565
+ if (value.startsWith("data:application/octet-stream;base64,")) {
4566
+ const base64Data = value.split(",")[1];
4567
+ if (base64Data) {
4568
+ return Buffer.from(base64Data, "base64");
4569
+ }
4570
+ }
4571
+ }
4572
+ return value;
4488
4573
  default:
4574
+ if (typeof value === "string") {
4575
+ if (value.startsWith("data:application/octet-stream;base64,")) {
4576
+ const base64Data = value.split(",")[1];
4577
+ if (base64Data) {
4578
+ return Buffer.from(base64Data, "base64");
4579
+ }
4580
+ }
4581
+ }
4489
4582
  return value;
4490
4583
  }
4491
4584
  }
@@ -4611,6 +4704,37 @@
4611
4704
  return value;
4612
4705
  }
4613
4706
  switch (property.type) {
4707
+ case "string": {
4708
+ if (typeof value === "string") return value;
4709
+ let isBuffer2 = false;
4710
+ let buf = null;
4711
+ if (Buffer.isBuffer(value)) {
4712
+ isBuffer2 = true;
4713
+ buf = value;
4714
+ } else if (typeof value === "object" && value !== null && value.type === "Buffer" && Array.isArray(value.data)) {
4715
+ isBuffer2 = true;
4716
+ buf = Buffer.from(value.data);
4717
+ }
4718
+ if (isBuffer2 && buf) {
4719
+ let isPrintable = true;
4720
+ for (let i = 0; i < buf.length; i++) {
4721
+ const b = buf[i];
4722
+ if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4723
+ isPrintable = false;
4724
+ break;
4725
+ }
4726
+ }
4727
+ return isPrintable ? buf.toString("utf8") : `data:application/octet-stream;base64,${buf.toString("base64")}`;
4728
+ }
4729
+ if (typeof value === "object" && value !== null) {
4730
+ try {
4731
+ return JSON.stringify(value);
4732
+ } catch {
4733
+ return String(value);
4734
+ }
4735
+ }
4736
+ return String(value);
4737
+ }
4614
4738
  case "relation":
4615
4739
  if (typeof value === "string" || typeof value === "number") {
4616
4740
  let relationDef = property.relation;
@@ -4694,8 +4818,29 @@
4694
4818
  }
4695
4819
  return null;
4696
4820
  }
4697
- default:
4821
+ default: {
4822
+ let isBuffer2 = false;
4823
+ let buf = null;
4824
+ if (Buffer.isBuffer(value)) {
4825
+ isBuffer2 = true;
4826
+ buf = value;
4827
+ } else if (typeof value === "object" && value !== null && value.type === "Buffer" && Array.isArray(value.data)) {
4828
+ isBuffer2 = true;
4829
+ buf = Buffer.from(value.data);
4830
+ }
4831
+ if (isBuffer2 && buf) {
4832
+ let isPrintable = true;
4833
+ for (let i = 0; i < buf.length; i++) {
4834
+ const b = buf[i];
4835
+ if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4836
+ isPrintable = false;
4837
+ break;
4838
+ }
4839
+ }
4840
+ return isPrintable ? buf.toString("utf8") : `data:application/octet-stream;base64,${buf.toString("base64")}`;
4841
+ }
4698
4842
  return value;
4843
+ }
4699
4844
  }
4700
4845
  }
4701
4846
  function normalizeScalarValues(data, properties, collection, resolvedRelations, options) {
@@ -5963,6 +6108,10 @@
5963
6108
  await this.resolveJoinPathRelations(entity, collection, collectionPath, parsedId, databaseId);
5964
6109
  return entity;
5965
6110
  } catch (e) {
6111
+ if (e instanceof Error && e.message.includes("not enough information to infer relation")) {
6112
+ console.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);
6113
+ console.error(`Hint: This usually means a relation in your drizzle schema is missing a reciprocal 'one()' or 'many()' definition. Run 'rebase schema generate' to fix this.`);
6114
+ }
5966
6115
  console.warn(`[EntityFetchService] db.query.findFirst failed for ${collectionPath}, falling back to db.select:`, e);
5967
6116
  }
5968
6117
  }
@@ -6023,6 +6172,10 @@
6023
6172
  const entities = results2.map((row) => this.drizzleResultToEntity(row, collection, collectionPath, idInfo, options.databaseId, idInfoArray));
6024
6173
  return entities;
6025
6174
  } catch (e) {
6175
+ if (e instanceof Error && e.message.includes("not enough information to infer relation")) {
6176
+ console.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);
6177
+ console.error(`Hint: This usually means a relation in your drizzle schema is missing a reciprocal 'one()' or 'many()' definition. Run 'rebase schema generate' to fix this.`);
6178
+ }
6026
6179
  console.warn(`[EntityFetchService] db.query.findMany failed for ${collectionPath}, falling back to db.select:`, e);
6027
6180
  }
6028
6181
  }
@@ -6292,6 +6445,10 @@
6292
6445
  await this.resolveJoinPathRelationsBatchRest(restRows, collection, collectionPath, idInfoArray, include);
6293
6446
  return restRows;
6294
6447
  } catch (e) {
6448
+ if (e instanceof Error && e.message.includes("not enough information to infer relation")) {
6449
+ console.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);
6450
+ console.error(`Hint: This usually means a relation in your drizzle schema is missing a reciprocal 'one()' or 'many()' definition. Run 'rebase schema generate' to fix this.`);
6451
+ }
6295
6452
  console.warn(`[fetchCollectionForRest] db.query.findMany failed for ${collectionPath}, falling back:`, e);
6296
6453
  }
6297
6454
  }
@@ -6372,6 +6529,10 @@
6372
6529
  await this.resolveJoinPathRelationsBatchRest([restRow], collection, collectionPath, idInfoArray, include);
6373
6530
  return restRow;
6374
6531
  } catch (e) {
6532
+ if (e instanceof Error && e.message.includes("not enough information to infer relation")) {
6533
+ console.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);
6534
+ console.error(`Hint: This usually means a relation in your drizzle schema is missing a reciprocal 'one()' or 'many()' definition. Run 'rebase schema generate' to fix this.`);
6535
+ }
6375
6536
  console.warn(`[fetchEntityForRest] db.query.findFirst failed for ${collectionPath}, falling back:`, e);
6376
6537
  }
6377
6538
  }
@@ -6630,7 +6791,7 @@
6630
6791
  targetColumnName = relation.localKey;
6631
6792
  } else if (relation.foreignKeyOnTarget) {
6632
6793
  targetColumnName = relation.foreignKeyOnTarget;
6633
- } else if (relation.joinPath && relation.joinPath.length > 0) {
6794
+ } else if (relation.joinPath && relation.joinPath.length === 1) {
6634
6795
  const targetTableName = getTableName(targetCollection);
6635
6796
  const relevantJoinStep = relation.joinPath.find((joinStep) => joinStep.table === targetTableName);
6636
6797
  if (relevantJoinStep) {
@@ -6641,6 +6802,8 @@
6641
6802
  const targetColumnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(relation.joinPath[0].on.to);
6642
6803
  targetColumnName = targetColumnNames[0];
6643
6804
  }
6805
+ } else if (relation.joinPath && relation.joinPath.length > 1) {
6806
+ break;
6644
6807
  } else {
6645
6808
  throw new Error(`Relation '${relationKey}' lacks configuration for path-based saving.`);
6646
6809
  }
@@ -6763,22 +6926,78 @@
6763
6926
  const pgError = this.extractPgError(error);
6764
6927
  if (pgError) {
6765
6928
  const detail = pgError.detail;
6929
+ const hint = pgError.hint;
6766
6930
  const constraint = pgError.constraint;
6767
6931
  const column = pgError.column;
6768
6932
  const table = pgError.table;
6933
+ const dataType = pgError.dataType;
6934
+ const pgMessage = pgError.message || "Unknown database error";
6935
+ const suffix = hint ? ` Hint: ${hint}` : "";
6936
+ const tableRef = table ?? collectionSlug;
6769
6937
  switch (pgError.code) {
6770
6938
  case "23503":
6771
- return new Error(detail ? `Foreign key constraint violated: ${detail}` : `Cannot save: a foreign key constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".`);
6939
+ return new Error(detail ? `Foreign key constraint violated: ${detail}${suffix}` : `Cannot save: a foreign key constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".${suffix}`);
6772
6940
  case "23505":
6773
- return new Error(detail ? `Duplicate value: ${detail}` : `Cannot save: a unique constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".`);
6941
+ return new Error(detail ? `Duplicate value: ${detail}${suffix}` : `Cannot save: a unique constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".${suffix}`);
6774
6942
  case "23502":
6775
- return new Error(`Missing required field: "${column ?? "unknown"}" in "${table ?? collectionSlug}" cannot be empty.`);
6943
+ return new Error(`Missing required field: "${column ?? "unknown"}" in "${tableRef}" cannot be empty.${suffix}`);
6776
6944
  case "23514":
6777
- return new Error(`Validation failed: a check constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".`);
6945
+ return new Error(`Validation failed: a check constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".${suffix}`);
6946
+ case "22P02":
6947
+ return new Error(`Invalid data format in "${collectionSlug}": ${pgMessage}${suffix}`);
6948
+ case "22001":
6949
+ return new Error(`Value too long for column "${column ?? "unknown"}" in "${tableRef}": ${pgMessage}${suffix}`);
6950
+ case "22003":
6951
+ return new Error(`Numeric value out of range for column "${column ?? "unknown"}" in "${tableRef}": ${pgMessage}${suffix}`);
6952
+ case "42703":
6953
+ return new Error(`Unknown column in "${tableRef}": ${pgMessage}. Check if your schema is up to date (run migrations).${suffix}`);
6954
+ case "42P01":
6955
+ return new Error(`Table not found for "${collectionSlug}": ${pgMessage}. Check if your schema is up to date (run migrations).${suffix}`);
6956
+ default: {
6957
+ const parts = [`Database error in "${collectionSlug}" [${pgError.code}]: ${pgMessage}`];
6958
+ if (detail) parts.push(`Detail: ${detail}`);
6959
+ if (column) parts.push(`Column: ${column}`);
6960
+ if (dataType) parts.push(`Data type: ${dataType}`);
6961
+ if (constraint) parts.push(`Constraint: ${constraint}`);
6962
+ if (hint) parts.push(`Hint: ${hint}`);
6963
+ return new Error(parts.join(". "));
6964
+ }
6965
+ }
6966
+ }
6967
+ const causeMessage = this.extractCauseMessage(error);
6968
+ if (causeMessage) {
6969
+ return new Error(`Database error in "${collectionSlug}": ${causeMessage}`);
6970
+ }
6971
+ if (error instanceof Error) {
6972
+ const cleaned = this.stripSqlFromMessage(error.message, collectionSlug);
6973
+ return new Error(cleaned);
6974
+ }
6975
+ return new Error(`Database error in "${collectionSlug}": ${String(error)}`);
6976
+ }
6977
+ /**
6978
+ * Walk the error cause chain and return the deepest meaningful message.
6979
+ */
6980
+ extractCauseMessage(error) {
6981
+ if (!error || typeof error !== "object") return null;
6982
+ const err = error;
6983
+ if (err.cause && typeof err.cause === "object") {
6984
+ const deeper = this.extractCauseMessage(err.cause);
6985
+ if (deeper) return deeper;
6986
+ if (err.cause instanceof Error && err.cause.message) {
6987
+ return err.cause.message;
6778
6988
  }
6779
6989
  }
6780
- if (error instanceof Error) return error;
6781
- return new Error(String(error));
6990
+ return null;
6991
+ }
6992
+ /**
6993
+ * Strip the raw SQL query from a Drizzle "Failed query: ..." message,
6994
+ * keeping only the error description.
6995
+ */
6996
+ stripSqlFromMessage(message, collectionSlug) {
6997
+ if (message.startsWith("Failed query:")) {
6998
+ return `Failed to save entity in "${collectionSlug}". Check server logs for details.`;
6999
+ }
7000
+ return message;
6782
7001
  }
6783
7002
  /**
6784
7003
  * Extract the underlying PostgreSQL error from a Drizzle wrapper.
@@ -6787,7 +7006,7 @@
6787
7006
  extractPgError(error) {
6788
7007
  if (!error || typeof error !== "object") return null;
6789
7008
  const err = error;
6790
- if (err.code && /^[0-9]{5}$/.test(err.code)) {
7009
+ if (err.code && /^[0-9A-Z]{5}$/.test(err.code)) {
6791
7010
  return err;
6792
7011
  }
6793
7012
  if (err.cause && typeof err.cause === "object") {
@@ -7075,6 +7294,7 @@
7075
7294
  branchService;
7076
7295
  user;
7077
7296
  data;
7297
+ client;
7078
7298
  /**
7079
7299
  * When true, realtime notifications are deferred until after the
7080
7300
  * wrapping transaction commits. Set by `withAuth` → `withTransaction`.
@@ -7103,6 +7323,14 @@
7103
7323
  } : {}
7104
7324
  };
7105
7325
  }
7326
+ /**
7327
+ * REST-optimised fetch service (include-aware eager-loading).
7328
+ * Delegates to the underlying EntityFetchService which already
7329
+ * implements the matching method signatures.
7330
+ */
7331
+ get restFetchService() {
7332
+ return this.entityService.getFetchService();
7333
+ }
7106
7334
  resolveCollectionCallbacks(collection, path2) {
7107
7335
  if (!collection && !path2) return {
7108
7336
  collection: void 0,
@@ -7156,7 +7384,8 @@
7156
7384
  const contextForCallback = {
7157
7385
  user: this.user,
7158
7386
  driver: this,
7159
- data: this.data
7387
+ data: this.data,
7388
+ client: this.client
7160
7389
  };
7161
7390
  return Promise.all(entities.map(async (entity) => {
7162
7391
  let fetched = entity;
@@ -7250,7 +7479,8 @@
7250
7479
  const contextForCallback = {
7251
7480
  user: this.user,
7252
7481
  driver: this,
7253
- data: this.data
7482
+ data: this.data,
7483
+ client: this.client
7254
7484
  };
7255
7485
  if (callbacks?.afterRead) {
7256
7486
  entity = await callbacks.afterRead({
@@ -7319,7 +7549,8 @@
7319
7549
  const contextForCallback = {
7320
7550
  user: this.user,
7321
7551
  driver: this,
7322
- data: this.data
7552
+ data: this.data,
7553
+ client: this.client
7323
7554
  };
7324
7555
  let previousValuesForHistory;
7325
7556
  if (status === "existing" && entityId) {
@@ -7354,6 +7585,14 @@
7354
7585
  if (result) updatedValues = mergeDeep(updatedValues, result);
7355
7586
  }
7356
7587
  }
7588
+ if (resolvedCollection?.properties) {
7589
+ updatedValues = updateDateAutoValues({
7590
+ inputValues: updatedValues,
7591
+ properties: resolvedCollection.properties,
7592
+ status: status ?? "new",
7593
+ timestampNowValue: /* @__PURE__ */ new Date()
7594
+ });
7595
+ }
7357
7596
  try {
7358
7597
  let savedEntity = await this.entityService.saveEntity(path2, updatedValues, entityId, resolvedCollection?.databaseId);
7359
7598
  if (savedEntity && (callbacks?.afterRead || propertyCallbacks?.afterRead)) {
@@ -7459,7 +7698,8 @@
7459
7698
  const contextForCallback = {
7460
7699
  user: this.user,
7461
7700
  driver: this,
7462
- data: this.data
7701
+ data: this.data,
7702
+ client: this.client
7463
7703
  };
7464
7704
  if (callbacks?.beforeDelete || propertyCallbacks?.beforeDelete) {
7465
7705
  if (callbacks?.beforeDelete) {
@@ -7786,6 +8026,7 @@
7786
8026
  txDelegate.entityService = txEntityService;
7787
8027
  txDelegate._deferNotifications = true;
7788
8028
  txDelegate._pendingNotifications = pendingNotifications;
8029
+ txDelegate.client = this.delegate.client;
7789
8030
  return await operation(txDelegate);
7790
8031
  });
7791
8032
  for (const notification of pendingNotifications) {
@@ -8067,6 +8308,12 @@
8067
8308
  references: [users.id]
8068
8309
  })
8069
8310
  }));
8311
+ const resolveColumnName = (propName, prop) => {
8312
+ if (prop && "columnName" in prop && typeof prop.columnName === "string") {
8313
+ return prop.columnName;
8314
+ }
8315
+ return toSnakeCase(propName);
8316
+ };
8070
8317
  const getPrimaryKeyProp = (collection) => {
8071
8318
  if (collection.properties) {
8072
8319
  const idPropEntry = Object.entries(collection.properties).find(([_, prop]) => "isId" in prop && Boolean(prop.isId));
@@ -8107,7 +8354,7 @@
8107
8354
  return !hasExplicitId && propName === "id";
8108
8355
  };
8109
8356
  const getDrizzleColumn = (propName, prop, collection, collections) => {
8110
- const colName = toSnakeCase(propName);
8357
+ const colName = resolveColumnName(propName, prop);
8111
8358
  let columnDefinition;
8112
8359
  switch (prop.type) {
8113
8360
  case "string": {
@@ -8179,6 +8426,9 @@
8179
8426
  } else {
8180
8427
  columnDefinition = `timestamp("${colName}", { withTimezone: true, mode: 'string' })`;
8181
8428
  }
8429
+ if (dateProp.autoValue === "on_create" || dateProp.autoValue === "on_update") {
8430
+ columnDefinition += `.default(sql\`now()\`)`;
8431
+ }
8182
8432
  break;
8183
8433
  }
8184
8434
  case "map":
@@ -8211,7 +8461,7 @@
8211
8461
  } catch {
8212
8462
  return null;
8213
8463
  }
8214
- const fkColumnName = toSnakeCase(relation.localKey);
8464
+ const fkColumnName = relation.localKey;
8215
8465
  const targetTableVar = getTableVarName(getTableName(targetCollection));
8216
8466
  const pkProp = getPrimaryKeyProp(targetCollection);
8217
8467
  const targetIdField = pkProp.name;
@@ -8399,7 +8649,7 @@
8399
8649
  Object.entries(collection.properties ?? {}).forEach(([propName, prop]) => {
8400
8650
  if ("enum" in prop && (prop.type === "string" || prop.type === "number") && prop.enum) {
8401
8651
  const enumVarName = getEnumVarName(collectionPath, propName);
8402
- const enumDbName = `${collectionPath}_${toSnakeCase(propName)}`;
8652
+ const enumDbName = `${collectionPath}_${resolveColumnName(propName, prop)}`;
8403
8653
  const values = Array.isArray(prop.enum) ? prop.enum.map((v) => String(v.id ?? v)) : Object.keys(prop.enum);
8404
8654
  if (values.length > 0) {
8405
8655
  schemaContent += `export const ${enumVarName} = pgEnum("${enumDbName}", [${values.map((v) => `'${v}'`).join(", ")}]);
@@ -8456,9 +8706,9 @@
8456
8706
  const targetId = getPrimaryKeyName(targetCollection);
8457
8707
  schemaContent += `export const ${tableVarName} = pgTable("${tableName}", {
8458
8708
  `;
8459
- schemaContent += ` ${sourceColumn}: ${sourceColType}("${toSnakeCase(sourceColumn)}").notNull().references(() => ${getTableVarName(getTableName(sourceCollection))}.${sourceId}, ${refOptions}),
8709
+ schemaContent += ` ${sourceColumn}: ${sourceColType}("${sourceColumn}").notNull().references(() => ${getTableVarName(getTableName(sourceCollection))}.${sourceId}, ${refOptions}),
8460
8710
  `;
8461
- schemaContent += ` ${targetColumn}: ${targetColType}("${toSnakeCase(targetColumn)}").notNull().references(() => ${getTableVarName(getTableName(targetCollection))}.${targetId}, ${refOptions}),
8711
+ schemaContent += ` ${targetColumn}: ${targetColType}("${targetColumn}").notNull().references(() => ${getTableVarName(getTableName(targetCollection))}.${targetId}, ${refOptions}),
8462
8712
  `;
8463
8713
  schemaContent += "}, (table) => ({\n";
8464
8714
  schemaContent += ` pk: primaryKey({ columns: [table.${sourceColumn}, table.${targetColumn}] })
@@ -8551,29 +8801,10 @@
8551
8801
  references: [${targetTableVar}.${getPrimaryKeyName(target)}],
8552
8802
  relationName: "${drizzleRelationName}"
8553
8803
  })`);
8554
- } else if (rel.direction === "inverse" && rel.foreignKeyOnTarget) {
8555
- const sourceIdField = getPrimaryKeyName(collection);
8804
+ } else if (rel.direction === "inverse") {
8556
8805
  tableRelations.push(` "${relationKey}": one(${targetTableVar}, {
8557
- fields: [${tableVarName}.${sourceIdField}],
8558
- references: [${targetTableVar}.${rel.foreignKeyOnTarget}],
8559
8806
  relationName: "${drizzleRelationName}"
8560
8807
  })`);
8561
- } else if (rel.direction === "inverse" && !rel.foreignKeyOnTarget) {
8562
- try {
8563
- const targetCollection = rel.target();
8564
- const targetResolvedRelations = resolveCollectionRelations(targetCollection);
8565
- const correspondingRelation = Object.values(targetResolvedRelations).find((targetRel) => targetRel.direction === "owning" && targetRel.cardinality === "one" && targetRel.target().slug === collection.slug);
8566
- if (correspondingRelation && correspondingRelation.localKey) {
8567
- const sourceIdField = getPrimaryKeyName(collection);
8568
- tableRelations.push(` "${relationKey}": one(${targetTableVar}, {
8569
- fields: [${tableVarName}.${sourceIdField}],
8570
- references: [${targetTableVar}.${correspondingRelation.localKey}],
8571
- relationName: "${drizzleRelationName}"
8572
- })`);
8573
- }
8574
- } catch (e) {
8575
- console.warn(`Could not resolve inverse one-to-one relation '${relationKey}':`, e);
8576
- }
8577
8808
  }
8578
8809
  } else if (rel.cardinality === "many") {
8579
8810
  if (rel.direction === "inverse" && rel.foreignKeyOnTarget) {
@@ -8601,6 +8832,32 @@
8601
8832
  console.warn(`Could not generate relation ${relationKey} for ${collection.name}:`, e);
8602
8833
  }
8603
8834
  }
8835
+ for (const otherCollection of collections) {
8836
+ if (otherCollection.slug === collection.slug) continue;
8837
+ const otherRelations = resolveCollectionRelations(otherCollection);
8838
+ for (const [otherKey, otherRel] of Object.entries(otherRelations)) {
8839
+ if (otherRel.direction === "inverse" && otherRel.foreignKeyOnTarget) {
8840
+ try {
8841
+ const otherTarget = otherRel.target();
8842
+ if (otherTarget.slug === collection.slug) {
8843
+ const drizzleRelationName = computeSharedRelationName(otherRel, otherCollection, collections);
8844
+ const deduplicationKey = `${drizzleRelationName}::owning`;
8845
+ if (!emittedRelationNames.has(deduplicationKey)) {
8846
+ const otherTableVar = getTableVarName(getTableName(otherCollection));
8847
+ const synthKey = `_synth_${otherTableVar}_${otherRel.foreignKeyOnTarget}`;
8848
+ tableRelations.push(` "${synthKey}": one(${otherTableVar}, {
8849
+ fields: [${tableVarName}.${otherRel.foreignKeyOnTarget}],
8850
+ references: [${otherTableVar}.${getPrimaryKeyName(otherCollection)}],
8851
+ relationName: "${drizzleRelationName}"
8852
+ })`);
8853
+ emittedRelationNames.add(deduplicationKey);
8854
+ }
8855
+ }
8856
+ } catch (e) {
8857
+ }
8858
+ }
8859
+ }
8860
+ }
8604
8861
  }
8605
8862
  if (tableRelations.length > 0) {
8606
8863
  const relVarName = `${tableVarName}Relations`;