@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.es.js CHANGED
@@ -124,7 +124,8 @@ function getDataSourceCapabilities(driver) {
124
124
  }
125
125
  const DEFAULT_ONE_OF_TYPE = "type";
126
126
  const DEFAULT_ONE_OF_VALUE = "value";
127
- const snakeCaseRegex = /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g;
127
+ const tokenizeRegex = /[A-Z]{2,}(?=[A-Z][a-z]|\b)|[A-Z]?[a-z]+|[0-9]+(?:[a-z](?![a-z]))?|[A-Z]/g;
128
+ const snakeCaseRegex = tokenizeRegex;
128
129
  const toSnakeCase = (str) => {
129
130
  const regExpMatchArray = str.match(snakeCaseRegex);
130
131
  if (!regExpMatchArray) return "";
@@ -1021,6 +1022,80 @@ function generateForeignKeyName(name) {
1021
1022
  const singularName = snakeCaseName.endsWith("s") ? snakeCaseName.slice(0, -1) : snakeCaseName;
1022
1023
  return `${singularName}_id`;
1023
1024
  }
1025
+ function updateDateAutoValues({
1026
+ inputValues,
1027
+ properties,
1028
+ status,
1029
+ timestampNowValue
1030
+ }) {
1031
+ return traverseValuesProperties(inputValues, properties, (inputValue, property) => {
1032
+ if (property.type === "date") {
1033
+ if (status === "existing" && property.autoValue === "on_update") {
1034
+ return timestampNowValue;
1035
+ } else if ((status === "new" || status === "copy") && (property.autoValue === "on_update" || property.autoValue === "on_create")) {
1036
+ return timestampNowValue;
1037
+ } else {
1038
+ return inputValue;
1039
+ }
1040
+ } else {
1041
+ return inputValue;
1042
+ }
1043
+ }) ?? {};
1044
+ }
1045
+ function traverseValuesProperties(inputValues, properties, operation) {
1046
+ const safeInputValues = inputValues ?? {};
1047
+ const updatedValues = Object.entries(properties).map(([key, property]) => {
1048
+ const inputValue = safeInputValues && safeInputValues[key];
1049
+ const updatedValue = traverseValueProperty(inputValue, property, operation);
1050
+ if (updatedValue === null) return null;
1051
+ if (updatedValue === void 0) return void 0;
1052
+ return {
1053
+ [key]: updatedValue
1054
+ };
1055
+ }).reduce((a, b) => ({
1056
+ ...a,
1057
+ ...b
1058
+ }), {});
1059
+ const result = mergeDeep(safeInputValues, updatedValues);
1060
+ if (!result || Object.keys(result).length === 0) return void 0;
1061
+ return result;
1062
+ }
1063
+ function traverseValueProperty(inputValue, property, operation) {
1064
+ let value;
1065
+ if (property.type === "map" && property.properties) {
1066
+ value = traverseValuesProperties(inputValue, property.properties, operation);
1067
+ } else if (property.type === "array") {
1068
+ const of = property.of;
1069
+ if (of && Array.isArray(inputValue) && !Array.isArray(of)) {
1070
+ value = inputValue.map((e) => traverseValueProperty(e, of, operation));
1071
+ } else if (of && Array.isArray(inputValue) && Array.isArray(of)) {
1072
+ value = inputValue.map((e, i) => {
1073
+ if (i < of.length) return traverseValueProperty(e, of[i], operation);
1074
+ return null;
1075
+ }).filter(Boolean);
1076
+ } else if (property.oneOf && Array.isArray(inputValue)) {
1077
+ const typeField = property.oneOf?.typeField ?? DEFAULT_ONE_OF_TYPE;
1078
+ const valueField = property.oneOf?.valueField ?? DEFAULT_ONE_OF_VALUE;
1079
+ value = inputValue.map((e) => {
1080
+ if (e === null) return null;
1081
+ if (typeof e !== "object") return e;
1082
+ const rec = e;
1083
+ const type = rec[typeField];
1084
+ const childProperty = property.oneOf?.properties[type];
1085
+ if (!type || !childProperty) return e;
1086
+ return {
1087
+ [typeField]: type,
1088
+ [valueField]: traverseValueProperty(rec[valueField], childProperty, operation)
1089
+ };
1090
+ });
1091
+ } else {
1092
+ value = inputValue;
1093
+ }
1094
+ } else {
1095
+ value = operation(inputValue, property);
1096
+ }
1097
+ return value;
1098
+ }
1024
1099
  function createRelationRef(id, path2) {
1025
1100
  return {
1026
1101
  id,
@@ -1717,8 +1792,8 @@ var logic = { exports: {} };
1717
1792
  return jsonLogic;
1718
1793
  });
1719
1794
  })(logic);
1720
- var getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols;
1721
- var hasOwnProperty$a = Object.prototype.hasOwnProperty;
1795
+ const { getOwnPropertyNames, getOwnPropertySymbols } = Object;
1796
+ const { hasOwnProperty: hasOwnProperty$a } = Object.prototype;
1722
1797
  function combineComparators(comparatorA, comparatorB) {
1723
1798
  return function isEqual(a, b, state) {
1724
1799
  return comparatorA(a, b, state) && comparatorB(a, b, state);
@@ -1729,38 +1804,45 @@ function createIsCircular(areItemsEqual) {
1729
1804
  if (!a || !b || typeof a !== "object" || typeof b !== "object") {
1730
1805
  return areItemsEqual(a, b, state);
1731
1806
  }
1732
- var cache = state.cache;
1733
- var cachedA = cache.get(a);
1734
- var cachedB = cache.get(b);
1807
+ const { cache } = state;
1808
+ const cachedA = cache.get(a);
1809
+ const cachedB = cache.get(b);
1735
1810
  if (cachedA && cachedB) {
1736
1811
  return cachedA === b && cachedB === a;
1737
1812
  }
1738
1813
  cache.set(a, b);
1739
1814
  cache.set(b, a);
1740
- var result = areItemsEqual(a, b, state);
1815
+ const result = areItemsEqual(a, b, state);
1741
1816
  cache.delete(a);
1742
1817
  cache.delete(b);
1743
1818
  return result;
1744
1819
  };
1745
1820
  }
1746
- function getShortTag(value) {
1747
- return value != null ? value[Symbol.toStringTag] : void 0;
1748
- }
1749
1821
  function getStrictProperties(object) {
1750
1822
  return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
1751
1823
  }
1752
- var hasOwn = Object.hasOwn || function(object, property) {
1753
- return hasOwnProperty$a.call(object, property);
1754
- };
1755
- function sameValueZeroEqual(a, b) {
1756
- return a === b || !a && !b && a !== a && b !== b;
1824
+ const hasOwn = (
1825
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1826
+ Object.hasOwn || ((object, property) => hasOwnProperty$a.call(object, property))
1827
+ );
1828
+ const PREACT_VNODE = "__v";
1829
+ const PREACT_OWNER = "__o";
1830
+ const REACT_OWNER = "_owner";
1831
+ const { getOwnPropertyDescriptor, keys: keys$4 } = Object;
1832
+ const sameValueEqual = (
1833
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1834
+ Object.is || function sameValueEqual2(a, b) {
1835
+ return a === b ? a !== 0 || 1 / a === 1 / b : a !== a && b !== b;
1836
+ }
1837
+ );
1838
+ function strictEqual(a, b) {
1839
+ return a === b;
1840
+ }
1841
+ function areArrayBuffersEqual(a, b) {
1842
+ return a.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a), new Uint8Array(b));
1757
1843
  }
1758
- var PREACT_VNODE = "__v";
1759
- var PREACT_OWNER = "__o";
1760
- var REACT_OWNER = "_owner";
1761
- var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, keys$4 = Object.keys;
1762
1844
  function areArraysEqual(a, b, state) {
1763
- var index = a.length;
1845
+ let index = a.length;
1764
1846
  if (b.length !== index) {
1765
1847
  return false;
1766
1848
  }
@@ -1771,35 +1853,35 @@ function areArraysEqual(a, b, state) {
1771
1853
  }
1772
1854
  return true;
1773
1855
  }
1856
+ function areDataViewsEqual(a, b) {
1857
+ return a.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a.buffer, a.byteOffset, a.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength));
1858
+ }
1774
1859
  function areDatesEqual(a, b) {
1775
- return sameValueZeroEqual(a.getTime(), b.getTime());
1860
+ return sameValueEqual(a.getTime(), b.getTime());
1776
1861
  }
1777
1862
  function areErrorsEqual(a, b) {
1778
1863
  return a.name === b.name && a.message === b.message && a.cause === b.cause && a.stack === b.stack;
1779
1864
  }
1780
- function areFunctionsEqual(a, b) {
1781
- return a === b;
1782
- }
1783
1865
  function areMapsEqual(a, b, state) {
1784
- var size = a.size;
1866
+ const size = a.size;
1785
1867
  if (size !== b.size) {
1786
1868
  return false;
1787
1869
  }
1788
1870
  if (!size) {
1789
1871
  return true;
1790
1872
  }
1791
- var matchedIndices = new Array(size);
1792
- var aIterable = a.entries();
1793
- var aResult;
1794
- var bResult;
1795
- var index = 0;
1873
+ const matchedIndices = new Array(size);
1874
+ const aIterable = a.entries();
1875
+ let aResult;
1876
+ let bResult;
1877
+ let index = 0;
1796
1878
  while (aResult = aIterable.next()) {
1797
1879
  if (aResult.done) {
1798
1880
  break;
1799
1881
  }
1800
- var bIterable = b.entries();
1801
- var hasMatch = false;
1802
- var matchIndex = 0;
1882
+ const bIterable = b.entries();
1883
+ let hasMatch = false;
1884
+ let matchIndex = 0;
1803
1885
  while (bResult = bIterable.next()) {
1804
1886
  if (bResult.done) {
1805
1887
  break;
@@ -1808,8 +1890,8 @@ function areMapsEqual(a, b, state) {
1808
1890
  matchIndex++;
1809
1891
  continue;
1810
1892
  }
1811
- var aEntry = aResult.value;
1812
- var bEntry = bResult.value;
1893
+ const aEntry = aResult.value;
1894
+ const bEntry = bResult.value;
1813
1895
  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)) {
1814
1896
  hasMatch = matchedIndices[matchIndex] = true;
1815
1897
  break;
@@ -1823,10 +1905,9 @@ function areMapsEqual(a, b, state) {
1823
1905
  }
1824
1906
  return true;
1825
1907
  }
1826
- var areNumbersEqual = sameValueZeroEqual;
1827
1908
  function areObjectsEqual(a, b, state) {
1828
- var properties = keys$4(a);
1829
- var index = properties.length;
1909
+ const properties = keys$4(a);
1910
+ let index = properties.length;
1830
1911
  if (keys$4(b).length !== index) {
1831
1912
  return false;
1832
1913
  }
@@ -1838,14 +1919,14 @@ function areObjectsEqual(a, b, state) {
1838
1919
  return true;
1839
1920
  }
1840
1921
  function areObjectsEqualStrict(a, b, state) {
1841
- var properties = getStrictProperties(a);
1842
- var index = properties.length;
1922
+ const properties = getStrictProperties(a);
1923
+ let index = properties.length;
1843
1924
  if (getStrictProperties(b).length !== index) {
1844
1925
  return false;
1845
1926
  }
1846
- var property;
1847
- var descriptorA;
1848
- var descriptorB;
1927
+ let property;
1928
+ let descriptorA;
1929
+ let descriptorB;
1849
1930
  while (index-- > 0) {
1850
1931
  property = properties[index];
1851
1932
  if (!isPropertyEqual(a, b, state, property)) {
@@ -1860,30 +1941,30 @@ function areObjectsEqualStrict(a, b, state) {
1860
1941
  return true;
1861
1942
  }
1862
1943
  function arePrimitiveWrappersEqual(a, b) {
1863
- return sameValueZeroEqual(a.valueOf(), b.valueOf());
1944
+ return sameValueEqual(a.valueOf(), b.valueOf());
1864
1945
  }
1865
1946
  function areRegExpsEqual(a, b) {
1866
1947
  return a.source === b.source && a.flags === b.flags;
1867
1948
  }
1868
1949
  function areSetsEqual(a, b, state) {
1869
- var size = a.size;
1950
+ const size = a.size;
1870
1951
  if (size !== b.size) {
1871
1952
  return false;
1872
1953
  }
1873
1954
  if (!size) {
1874
1955
  return true;
1875
1956
  }
1876
- var matchedIndices = new Array(size);
1877
- var aIterable = a.values();
1878
- var aResult;
1879
- var bResult;
1957
+ const matchedIndices = new Array(size);
1958
+ const aIterable = a.values();
1959
+ let aResult;
1960
+ let bResult;
1880
1961
  while (aResult = aIterable.next()) {
1881
1962
  if (aResult.done) {
1882
1963
  break;
1883
1964
  }
1884
- var bIterable = b.values();
1885
- var hasMatch = false;
1886
- var matchIndex = 0;
1965
+ const bIterable = b.values();
1966
+ let hasMatch = false;
1967
+ let matchIndex = 0;
1887
1968
  while (bResult = bIterable.next()) {
1888
1969
  if (bResult.done) {
1889
1970
  break;
@@ -1901,8 +1982,8 @@ function areSetsEqual(a, b, state) {
1901
1982
  return true;
1902
1983
  }
1903
1984
  function areTypedArraysEqual(a, b) {
1904
- var index = a.length;
1905
- if (b.length !== index) {
1985
+ let index = a.byteLength;
1986
+ if (b.byteLength !== index || a.byteOffset !== b.byteOffset) {
1906
1987
  return false;
1907
1988
  }
1908
1989
  while (index-- > 0) {
@@ -1921,23 +2002,10 @@ function isPropertyEqual(a, b, state, property) {
1921
2002
  }
1922
2003
  return hasOwn(b, property) && state.equals(a[property], b[property], property, property, a, b, state);
1923
2004
  }
1924
- var ARGUMENTS_TAG = "[object Arguments]";
1925
- var BOOLEAN_TAG = "[object Boolean]";
1926
- var DATE_TAG = "[object Date]";
1927
- var ERROR_TAG = "[object Error]";
1928
- var MAP_TAG = "[object Map]";
1929
- var NUMBER_TAG = "[object Number]";
1930
- var OBJECT_TAG = "[object Object]";
1931
- var REG_EXP_TAG = "[object RegExp]";
1932
- var SET_TAG = "[object Set]";
1933
- var STRING_TAG = "[object String]";
1934
- var URL_TAG = "[object URL]";
1935
- var isArray$4 = Array.isArray;
1936
- var isTypedArray$2 = typeof ArrayBuffer === "function" && ArrayBuffer.isView ? ArrayBuffer.isView : null;
1937
- var assign = Object.assign;
1938
- var getTag$4 = Object.prototype.toString.call.bind(Object.prototype.toString);
1939
- function createEqualityComparator(_a) {
1940
- 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;
2005
+ const toString = Object.prototype.toString;
2006
+ function createEqualityComparator(config) {
2007
+ const supportedComparatorMap = createSupportedComparatorMap(config);
2008
+ const { areArraysEqual: areArraysEqual2, areDatesEqual: areDatesEqual2, areFunctionsEqual, areMapsEqual: areMapsEqual2, areNumbersEqual, areObjectsEqual: areObjectsEqual2, areRegExpsEqual: areRegExpsEqual2, areSetsEqual: areSetsEqual2, getUnsupportedCustomComparator } = config;
1941
2009
  return function comparator(a, b, state) {
1942
2010
  if (a === b) {
1943
2011
  return true;
@@ -1945,32 +2013,29 @@ function createEqualityComparator(_a) {
1945
2013
  if (a == null || b == null) {
1946
2014
  return false;
1947
2015
  }
1948
- var type = typeof a;
2016
+ const type = typeof a;
1949
2017
  if (type !== typeof b) {
1950
2018
  return false;
1951
2019
  }
1952
2020
  if (type !== "object") {
1953
- if (type === "number") {
1954
- return areNumbersEqual2(a, b, state);
2021
+ if (type === "number" || type === "bigint") {
2022
+ return areNumbersEqual(a, b, state);
1955
2023
  }
1956
2024
  if (type === "function") {
1957
- return areFunctionsEqual2(a, b, state);
2025
+ return areFunctionsEqual(a, b, state);
1958
2026
  }
1959
2027
  return false;
1960
2028
  }
1961
- var constructor = a.constructor;
2029
+ const constructor = a.constructor;
1962
2030
  if (constructor !== b.constructor) {
1963
2031
  return false;
1964
2032
  }
1965
2033
  if (constructor === Object) {
1966
2034
  return areObjectsEqual2(a, b, state);
1967
2035
  }
1968
- if (isArray$4(a)) {
2036
+ if (constructor === Array) {
1969
2037
  return areArraysEqual2(a, b, state);
1970
2038
  }
1971
- if (isTypedArray$2 != null && isTypedArray$2(a)) {
1972
- return areTypedArraysEqual2(a, b, state);
1973
- }
1974
2039
  if (constructor === Date) {
1975
2040
  return areDatesEqual2(a, b, state);
1976
2041
  }
@@ -1983,79 +2048,55 @@ function createEqualityComparator(_a) {
1983
2048
  if (constructor === Set) {
1984
2049
  return areSetsEqual2(a, b, state);
1985
2050
  }
1986
- var tag = getTag$4(a);
1987
- if (tag === DATE_TAG) {
1988
- return areDatesEqual2(a, b, state);
1989
- }
1990
- if (tag === REG_EXP_TAG) {
1991
- return areRegExpsEqual2(a, b, state);
1992
- }
1993
- if (tag === MAP_TAG) {
1994
- return areMapsEqual2(a, b, state);
1995
- }
1996
- if (tag === SET_TAG) {
1997
- return areSetsEqual2(a, b, state);
1998
- }
1999
- if (tag === OBJECT_TAG) {
2000
- return typeof a.then !== "function" && typeof b.then !== "function" && areObjectsEqual2(a, b, state);
2051
+ if (constructor === Promise) {
2052
+ return false;
2001
2053
  }
2002
- if (tag === URL_TAG) {
2003
- return areUrlsEqual2(a, b, state);
2054
+ if (Array.isArray(a)) {
2055
+ return areArraysEqual2(a, b, state);
2004
2056
  }
2005
- if (tag === ERROR_TAG) {
2006
- return areErrorsEqual2(a, b, state);
2057
+ const tag = toString.call(a);
2058
+ const supportedComparator = supportedComparatorMap[tag];
2059
+ if (supportedComparator) {
2060
+ return supportedComparator(a, b, state);
2007
2061
  }
2008
- if (tag === ARGUMENTS_TAG) {
2009
- return areObjectsEqual2(a, b, state);
2010
- }
2011
- if (tag === BOOLEAN_TAG || tag === NUMBER_TAG || tag === STRING_TAG) {
2012
- return arePrimitiveWrappersEqual2(a, b, state);
2013
- }
2014
- if (unknownTagComparators) {
2015
- var unknownTagComparator = unknownTagComparators[tag];
2016
- if (!unknownTagComparator) {
2017
- var shortTag = getShortTag(a);
2018
- if (shortTag) {
2019
- unknownTagComparator = unknownTagComparators[shortTag];
2020
- }
2021
- }
2022
- if (unknownTagComparator) {
2023
- return unknownTagComparator(a, b, state);
2024
- }
2062
+ const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a, b, state, tag);
2063
+ if (unsupportedCustomComparator) {
2064
+ return unsupportedCustomComparator(a, b, state);
2025
2065
  }
2026
2066
  return false;
2027
2067
  };
2028
2068
  }
2029
- function createEqualityComparatorConfig(_a) {
2030
- var circular = _a.circular, createCustomConfig = _a.createCustomConfig, strict = _a.strict;
2031
- var config = {
2069
+ function createEqualityComparatorConfig({ circular, createCustomConfig, strict }) {
2070
+ let config = {
2071
+ areArrayBuffersEqual,
2032
2072
  areArraysEqual: strict ? areObjectsEqualStrict : areArraysEqual,
2073
+ areDataViewsEqual,
2033
2074
  areDatesEqual,
2034
2075
  areErrorsEqual,
2035
- areFunctionsEqual,
2076
+ areFunctionsEqual: strictEqual,
2036
2077
  areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
2037
- areNumbersEqual,
2078
+ areNumbersEqual: sameValueEqual,
2038
2079
  areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
2039
2080
  arePrimitiveWrappersEqual,
2040
2081
  areRegExpsEqual,
2041
2082
  areSetsEqual: strict ? combineComparators(areSetsEqual, areObjectsEqualStrict) : areSetsEqual,
2042
- areTypedArraysEqual: strict ? areObjectsEqualStrict : areTypedArraysEqual,
2083
+ areTypedArraysEqual: strict ? combineComparators(areTypedArraysEqual, areObjectsEqualStrict) : areTypedArraysEqual,
2043
2084
  areUrlsEqual,
2044
- unknownTagComparators: void 0
2085
+ getUnsupportedCustomComparator: void 0
2045
2086
  };
2046
2087
  if (createCustomConfig) {
2047
- config = assign({}, config, createCustomConfig(config));
2088
+ config = Object.assign({}, config, createCustomConfig(config));
2048
2089
  }
2049
2090
  if (circular) {
2050
- var areArraysEqual$1 = createIsCircular(config.areArraysEqual);
2051
- var areMapsEqual$1 = createIsCircular(config.areMapsEqual);
2052
- var areObjectsEqual$1 = createIsCircular(config.areObjectsEqual);
2053
- var areSetsEqual$1 = createIsCircular(config.areSetsEqual);
2054
- config = assign({}, config, {
2055
- areArraysEqual: areArraysEqual$1,
2056
- areMapsEqual: areMapsEqual$1,
2057
- areObjectsEqual: areObjectsEqual$1,
2058
- areSetsEqual: areSetsEqual$1
2091
+ const areArraysEqual2 = createIsCircular(config.areArraysEqual);
2092
+ const areMapsEqual2 = createIsCircular(config.areMapsEqual);
2093
+ const areObjectsEqual2 = createIsCircular(config.areObjectsEqual);
2094
+ const areSetsEqual2 = createIsCircular(config.areSetsEqual);
2095
+ config = Object.assign({}, config, {
2096
+ areArraysEqual: areArraysEqual2,
2097
+ areMapsEqual: areMapsEqual2,
2098
+ areObjectsEqual: areObjectsEqual2,
2099
+ areSetsEqual: areSetsEqual2
2059
2100
  });
2060
2101
  }
2061
2102
  return config;
@@ -2065,11 +2106,10 @@ function createInternalEqualityComparator(compare) {
2065
2106
  return compare(a, b, state);
2066
2107
  };
2067
2108
  }
2068
- function createIsEqual(_a) {
2069
- var circular = _a.circular, comparator = _a.comparator, createState = _a.createState, equals = _a.equals, strict = _a.strict;
2109
+ function createIsEqual({ circular, comparator, createState, equals, strict }) {
2070
2110
  if (createState) {
2071
2111
  return function isEqual(a, b) {
2072
- var _a2 = createState(), _b = _a2.cache, cache = _b === void 0 ? circular ? /* @__PURE__ */ new WeakMap() : void 0 : _b, meta = _a2.meta;
2112
+ const { cache = circular ? /* @__PURE__ */ new WeakMap() : void 0, meta } = createState();
2073
2113
  return comparator(a, b, {
2074
2114
  cache,
2075
2115
  equals,
@@ -2088,7 +2128,7 @@ function createIsEqual(_a) {
2088
2128
  });
2089
2129
  };
2090
2130
  }
2091
- var state = {
2131
+ const state = {
2092
2132
  cache: void 0,
2093
2133
  equals,
2094
2134
  meta: void 0,
@@ -2098,7 +2138,50 @@ function createIsEqual(_a) {
2098
2138
  return comparator(a, b, state);
2099
2139
  };
2100
2140
  }
2101
- var deepEqual = createCustomEqual();
2141
+ 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 }) {
2142
+ return {
2143
+ "[object Arguments]": areObjectsEqual2,
2144
+ "[object Array]": areArraysEqual2,
2145
+ "[object ArrayBuffer]": areArrayBuffersEqual2,
2146
+ "[object AsyncGeneratorFunction]": areFunctionsEqual,
2147
+ "[object BigInt]": areNumbersEqual,
2148
+ "[object BigInt64Array]": areTypedArraysEqual2,
2149
+ "[object BigUint64Array]": areTypedArraysEqual2,
2150
+ "[object Boolean]": arePrimitiveWrappersEqual2,
2151
+ "[object DataView]": areDataViewsEqual2,
2152
+ "[object Date]": areDatesEqual2,
2153
+ // If an error tag, it should be tested explicitly. Like RegExp, the properties are not
2154
+ // enumerable, and therefore will give false positives if tested like a standard object.
2155
+ "[object Error]": areErrorsEqual2,
2156
+ "[object Float16Array]": areTypedArraysEqual2,
2157
+ "[object Float32Array]": areTypedArraysEqual2,
2158
+ "[object Float64Array]": areTypedArraysEqual2,
2159
+ "[object Function]": areFunctionsEqual,
2160
+ "[object GeneratorFunction]": areFunctionsEqual,
2161
+ "[object Int8Array]": areTypedArraysEqual2,
2162
+ "[object Int16Array]": areTypedArraysEqual2,
2163
+ "[object Int32Array]": areTypedArraysEqual2,
2164
+ "[object Map]": areMapsEqual2,
2165
+ "[object Number]": arePrimitiveWrappersEqual2,
2166
+ "[object Object]": (a, b, state) => (
2167
+ // The exception for value comparison is custom `Promise`-like class instances. These should
2168
+ // be treated the same as standard `Promise` objects, which means strict equality, and if
2169
+ // it reaches this point then that strict equality comparison has already failed.
2170
+ typeof a.then !== "function" && typeof b.then !== "function" && areObjectsEqual2(a, b, state)
2171
+ ),
2172
+ // For RegExp, the properties are not enumerable, and therefore will give false positives if
2173
+ // tested like a standard object.
2174
+ "[object RegExp]": areRegExpsEqual2,
2175
+ "[object Set]": areSetsEqual2,
2176
+ "[object String]": arePrimitiveWrappersEqual2,
2177
+ "[object URL]": areUrlsEqual2,
2178
+ "[object Uint8Array]": areTypedArraysEqual2,
2179
+ "[object Uint8ClampedArray]": areTypedArraysEqual2,
2180
+ "[object Uint16Array]": areTypedArraysEqual2,
2181
+ "[object Uint32Array]": areTypedArraysEqual2
2182
+ };
2183
+ }
2184
+ const deepEqual = createCustomEqual();
2102
2185
  createCustomEqual({ strict: true });
2103
2186
  createCustomEqual({ circular: true });
2104
2187
  createCustomEqual({
@@ -2106,37 +2189,26 @@ createCustomEqual({
2106
2189
  strict: true
2107
2190
  });
2108
2191
  createCustomEqual({
2109
- createInternalComparator: function() {
2110
- return sameValueZeroEqual;
2111
- }
2192
+ createInternalComparator: () => sameValueEqual
2112
2193
  });
2113
2194
  createCustomEqual({
2114
2195
  strict: true,
2115
- createInternalComparator: function() {
2116
- return sameValueZeroEqual;
2117
- }
2196
+ createInternalComparator: () => sameValueEqual
2118
2197
  });
2119
2198
  createCustomEqual({
2120
2199
  circular: true,
2121
- createInternalComparator: function() {
2122
- return sameValueZeroEqual;
2123
- }
2200
+ createInternalComparator: () => sameValueEqual
2124
2201
  });
2125
2202
  createCustomEqual({
2126
2203
  circular: true,
2127
- createInternalComparator: function() {
2128
- return sameValueZeroEqual;
2129
- },
2204
+ createInternalComparator: () => sameValueEqual,
2130
2205
  strict: true
2131
2206
  });
2132
- function createCustomEqual(options) {
2133
- if (options === void 0) {
2134
- options = {};
2135
- }
2136
- 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;
2137
- var config = createEqualityComparatorConfig(options);
2138
- var comparator = createEqualityComparator(config);
2139
- var equals = createCustomInternalComparator ? createCustomInternalComparator(comparator) : createInternalEqualityComparator(comparator);
2207
+ function createCustomEqual(options = {}) {
2208
+ const { circular = false, createInternalComparator: createCustomInternalComparator, createState, strict = false } = options;
2209
+ const config = createEqualityComparatorConfig(options);
2210
+ const comparator = createEqualityComparator(config);
2211
+ const equals = createCustomInternalComparator ? createCustomInternalComparator(comparator) : createInternalEqualityComparator(comparator);
2140
2212
  return createIsEqual({ circular, comparator, createState, equals, strict });
2141
2213
  }
2142
2214
  function listCacheClear$1() {
@@ -2611,8 +2683,8 @@ isBuffer$2.exports;
2611
2683
  var freeExports = exports$1 && !exports$1.nodeType && exports$1;
2612
2684
  var freeModule = freeExports && true && module && !module.nodeType && module;
2613
2685
  var moduleExports = freeModule && freeModule.exports === freeExports;
2614
- var Buffer = moduleExports ? root2.Buffer : void 0;
2615
- var nativeIsBuffer = Buffer ? Buffer.isBuffer : void 0;
2686
+ var Buffer2 = moduleExports ? root2.Buffer : void 0;
2687
+ var nativeIsBuffer = Buffer2 ? Buffer2.isBuffer : void 0;
2616
2688
  var isBuffer2 = nativeIsBuffer || stubFalse2;
2617
2689
  module.exports = isBuffer2;
2618
2690
  })(isBuffer$2, isBuffer$2.exports);
@@ -2777,7 +2849,7 @@ _cloneBuffer.exports;
2777
2849
  var freeExports = exports$1 && !exports$1.nodeType && exports$1;
2778
2850
  var freeModule = freeExports && true && module && !module.nodeType && module;
2779
2851
  var moduleExports = freeModule && freeModule.exports === freeExports;
2780
- var Buffer = moduleExports ? root2.Buffer : void 0, allocUnsafe = Buffer ? Buffer.allocUnsafe : void 0;
2852
+ var Buffer2 = moduleExports ? root2.Buffer : void 0, allocUnsafe = Buffer2 ? Buffer2.allocUnsafe : void 0;
2781
2853
  function cloneBuffer2(buffer, isDeep) {
2782
2854
  if (isDeep) {
2783
2855
  return buffer.slice();
@@ -3386,7 +3458,10 @@ class CollectionRegistry {
3386
3458
  if (!relation) {
3387
3459
  throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'`);
3388
3460
  }
3389
- currentCollection = relation.target();
3461
+ const target = relation.target();
3462
+ const targetRelationKey = relation.relationName || target.slug;
3463
+ const targetSlug = relation.overrides?.slug ?? targetRelationKey;
3464
+ currentCollection = this.get(targetSlug) || this.normalizeCollection(target);
3390
3465
  if (i + 1 < pathSegments.length) ;
3391
3466
  }
3392
3467
  return currentCollection;
@@ -3435,7 +3510,7 @@ class CollectionRegistry {
3435
3510
  if (!subcollection) {
3436
3511
  throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
3437
3512
  }
3438
- currentCollection = subcollection;
3513
+ currentCollection = this.get(subcollection.slug) || this.normalizeCollection(subcollection);
3439
3514
  collections.push(currentCollection);
3440
3515
  }
3441
3516
  }
@@ -4477,7 +4552,25 @@ function serializePropertyToServer(value, property) {
4477
4552
  return result;
4478
4553
  }
4479
4554
  return value;
4555
+ case "string":
4556
+ if (typeof value === "string") {
4557
+ if (value.startsWith("data:application/octet-stream;base64,")) {
4558
+ const base64Data = value.split(",")[1];
4559
+ if (base64Data) {
4560
+ return Buffer.from(base64Data, "base64");
4561
+ }
4562
+ }
4563
+ }
4564
+ return value;
4480
4565
  default:
4566
+ if (typeof value === "string") {
4567
+ if (value.startsWith("data:application/octet-stream;base64,")) {
4568
+ const base64Data = value.split(",")[1];
4569
+ if (base64Data) {
4570
+ return Buffer.from(base64Data, "base64");
4571
+ }
4572
+ }
4573
+ }
4481
4574
  return value;
4482
4575
  }
4483
4576
  }
@@ -4603,6 +4696,37 @@ function parsePropertyFromServer(value, property, collection, propertyKey) {
4603
4696
  return value;
4604
4697
  }
4605
4698
  switch (property.type) {
4699
+ case "string": {
4700
+ if (typeof value === "string") return value;
4701
+ let isBuffer2 = false;
4702
+ let buf = null;
4703
+ if (Buffer.isBuffer(value)) {
4704
+ isBuffer2 = true;
4705
+ buf = value;
4706
+ } else if (typeof value === "object" && value !== null && value.type === "Buffer" && Array.isArray(value.data)) {
4707
+ isBuffer2 = true;
4708
+ buf = Buffer.from(value.data);
4709
+ }
4710
+ if (isBuffer2 && buf) {
4711
+ let isPrintable = true;
4712
+ for (let i = 0; i < buf.length; i++) {
4713
+ const b = buf[i];
4714
+ if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4715
+ isPrintable = false;
4716
+ break;
4717
+ }
4718
+ }
4719
+ return isPrintable ? buf.toString("utf8") : `data:application/octet-stream;base64,${buf.toString("base64")}`;
4720
+ }
4721
+ if (typeof value === "object" && value !== null) {
4722
+ try {
4723
+ return JSON.stringify(value);
4724
+ } catch {
4725
+ return String(value);
4726
+ }
4727
+ }
4728
+ return String(value);
4729
+ }
4606
4730
  case "relation":
4607
4731
  if (typeof value === "string" || typeof value === "number") {
4608
4732
  let relationDef = property.relation;
@@ -4686,8 +4810,29 @@ function parsePropertyFromServer(value, property, collection, propertyKey) {
4686
4810
  }
4687
4811
  return null;
4688
4812
  }
4689
- default:
4813
+ default: {
4814
+ let isBuffer2 = false;
4815
+ let buf = null;
4816
+ if (Buffer.isBuffer(value)) {
4817
+ isBuffer2 = true;
4818
+ buf = value;
4819
+ } else if (typeof value === "object" && value !== null && value.type === "Buffer" && Array.isArray(value.data)) {
4820
+ isBuffer2 = true;
4821
+ buf = Buffer.from(value.data);
4822
+ }
4823
+ if (isBuffer2 && buf) {
4824
+ let isPrintable = true;
4825
+ for (let i = 0; i < buf.length; i++) {
4826
+ const b = buf[i];
4827
+ if ((b < 32 || b > 126) && b !== 9 && b !== 10 && b !== 13) {
4828
+ isPrintable = false;
4829
+ break;
4830
+ }
4831
+ }
4832
+ return isPrintable ? buf.toString("utf8") : `data:application/octet-stream;base64,${buf.toString("base64")}`;
4833
+ }
4690
4834
  return value;
4835
+ }
4691
4836
  }
4692
4837
  }
4693
4838
  function normalizeScalarValues(data, properties, collection, resolvedRelations, options) {
@@ -5955,6 +6100,10 @@ class EntityFetchService {
5955
6100
  await this.resolveJoinPathRelations(entity, collection, collectionPath, parsedId, databaseId);
5956
6101
  return entity;
5957
6102
  } catch (e) {
6103
+ if (e instanceof Error && e.message.includes("not enough information to infer relation")) {
6104
+ console.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);
6105
+ 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.`);
6106
+ }
5958
6107
  console.warn(`[EntityFetchService] db.query.findFirst failed for ${collectionPath}, falling back to db.select:`, e);
5959
6108
  }
5960
6109
  }
@@ -6015,6 +6164,10 @@ class EntityFetchService {
6015
6164
  const entities = results2.map((row) => this.drizzleResultToEntity(row, collection, collectionPath, idInfo, options.databaseId, idInfoArray));
6016
6165
  return entities;
6017
6166
  } catch (e) {
6167
+ if (e instanceof Error && e.message.includes("not enough information to infer relation")) {
6168
+ console.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);
6169
+ 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.`);
6170
+ }
6018
6171
  console.warn(`[EntityFetchService] db.query.findMany failed for ${collectionPath}, falling back to db.select:`, e);
6019
6172
  }
6020
6173
  }
@@ -6284,6 +6437,10 @@ class EntityFetchService {
6284
6437
  await this.resolveJoinPathRelationsBatchRest(restRows, collection, collectionPath, idInfoArray, include);
6285
6438
  return restRows;
6286
6439
  } catch (e) {
6440
+ if (e instanceof Error && e.message.includes("not enough information to infer relation")) {
6441
+ console.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);
6442
+ 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.`);
6443
+ }
6287
6444
  console.warn(`[fetchCollectionForRest] db.query.findMany failed for ${collectionPath}, falling back:`, e);
6288
6445
  }
6289
6446
  }
@@ -6364,6 +6521,10 @@ class EntityFetchService {
6364
6521
  await this.resolveJoinPathRelationsBatchRest([restRow], collection, collectionPath, idInfoArray, include);
6365
6522
  return restRow;
6366
6523
  } catch (e) {
6524
+ if (e instanceof Error && e.message.includes("not enough information to infer relation")) {
6525
+ console.error(`[EntityFetchService] Relation inference error for collection '${collectionPath}': ${e.message}`);
6526
+ 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.`);
6527
+ }
6367
6528
  console.warn(`[fetchEntityForRest] db.query.findFirst failed for ${collectionPath}, falling back:`, e);
6368
6529
  }
6369
6530
  }
@@ -6622,7 +6783,7 @@ class EntityPersistService {
6622
6783
  targetColumnName = relation.localKey;
6623
6784
  } else if (relation.foreignKeyOnTarget) {
6624
6785
  targetColumnName = relation.foreignKeyOnTarget;
6625
- } else if (relation.joinPath && relation.joinPath.length > 0) {
6786
+ } else if (relation.joinPath && relation.joinPath.length === 1) {
6626
6787
  const targetTableName = getTableName(targetCollection);
6627
6788
  const relevantJoinStep = relation.joinPath.find((joinStep) => joinStep.table === targetTableName);
6628
6789
  if (relevantJoinStep) {
@@ -6633,6 +6794,8 @@ class EntityPersistService {
6633
6794
  const targetColumnNames = DrizzleConditionBuilder.getColumnNamesFromColumns(relation.joinPath[0].on.to);
6634
6795
  targetColumnName = targetColumnNames[0];
6635
6796
  }
6797
+ } else if (relation.joinPath && relation.joinPath.length > 1) {
6798
+ break;
6636
6799
  } else {
6637
6800
  throw new Error(`Relation '${relationKey}' lacks configuration for path-based saving.`);
6638
6801
  }
@@ -6755,22 +6918,78 @@ class EntityPersistService {
6755
6918
  const pgError = this.extractPgError(error);
6756
6919
  if (pgError) {
6757
6920
  const detail = pgError.detail;
6921
+ const hint = pgError.hint;
6758
6922
  const constraint = pgError.constraint;
6759
6923
  const column = pgError.column;
6760
6924
  const table = pgError.table;
6925
+ const dataType = pgError.dataType;
6926
+ const pgMessage = pgError.message || "Unknown database error";
6927
+ const suffix = hint ? ` Hint: ${hint}` : "";
6928
+ const tableRef = table ?? collectionSlug;
6761
6929
  switch (pgError.code) {
6762
6930
  case "23503":
6763
- return new Error(detail ? `Foreign key constraint violated: ${detail}` : `Cannot save: a foreign key constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".`);
6931
+ return new Error(detail ? `Foreign key constraint violated: ${detail}${suffix}` : `Cannot save: a foreign key constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".${suffix}`);
6764
6932
  case "23505":
6765
- return new Error(detail ? `Duplicate value: ${detail}` : `Cannot save: a unique constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".`);
6933
+ return new Error(detail ? `Duplicate value: ${detail}${suffix}` : `Cannot save: a unique constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".${suffix}`);
6766
6934
  case "23502":
6767
- return new Error(`Missing required field: "${column ?? "unknown"}" in "${table ?? collectionSlug}" cannot be empty.`);
6935
+ return new Error(`Missing required field: "${column ?? "unknown"}" in "${tableRef}" cannot be empty.${suffix}`);
6768
6936
  case "23514":
6769
- return new Error(`Validation failed: a check constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".`);
6937
+ return new Error(`Validation failed: a check constraint${constraint ? ` (${constraint})` : ""} was violated in "${collectionSlug}".${suffix}`);
6938
+ case "22P02":
6939
+ return new Error(`Invalid data format in "${collectionSlug}": ${pgMessage}${suffix}`);
6940
+ case "22001":
6941
+ return new Error(`Value too long for column "${column ?? "unknown"}" in "${tableRef}": ${pgMessage}${suffix}`);
6942
+ case "22003":
6943
+ return new Error(`Numeric value out of range for column "${column ?? "unknown"}" in "${tableRef}": ${pgMessage}${suffix}`);
6944
+ case "42703":
6945
+ return new Error(`Unknown column in "${tableRef}": ${pgMessage}. Check if your schema is up to date (run migrations).${suffix}`);
6946
+ case "42P01":
6947
+ return new Error(`Table not found for "${collectionSlug}": ${pgMessage}. Check if your schema is up to date (run migrations).${suffix}`);
6948
+ default: {
6949
+ const parts = [`Database error in "${collectionSlug}" [${pgError.code}]: ${pgMessage}`];
6950
+ if (detail) parts.push(`Detail: ${detail}`);
6951
+ if (column) parts.push(`Column: ${column}`);
6952
+ if (dataType) parts.push(`Data type: ${dataType}`);
6953
+ if (constraint) parts.push(`Constraint: ${constraint}`);
6954
+ if (hint) parts.push(`Hint: ${hint}`);
6955
+ return new Error(parts.join(". "));
6956
+ }
6957
+ }
6958
+ }
6959
+ const causeMessage = this.extractCauseMessage(error);
6960
+ if (causeMessage) {
6961
+ return new Error(`Database error in "${collectionSlug}": ${causeMessage}`);
6962
+ }
6963
+ if (error instanceof Error) {
6964
+ const cleaned = this.stripSqlFromMessage(error.message, collectionSlug);
6965
+ return new Error(cleaned);
6966
+ }
6967
+ return new Error(`Database error in "${collectionSlug}": ${String(error)}`);
6968
+ }
6969
+ /**
6970
+ * Walk the error cause chain and return the deepest meaningful message.
6971
+ */
6972
+ extractCauseMessage(error) {
6973
+ if (!error || typeof error !== "object") return null;
6974
+ const err = error;
6975
+ if (err.cause && typeof err.cause === "object") {
6976
+ const deeper = this.extractCauseMessage(err.cause);
6977
+ if (deeper) return deeper;
6978
+ if (err.cause instanceof Error && err.cause.message) {
6979
+ return err.cause.message;
6770
6980
  }
6771
6981
  }
6772
- if (error instanceof Error) return error;
6773
- return new Error(String(error));
6982
+ return null;
6983
+ }
6984
+ /**
6985
+ * Strip the raw SQL query from a Drizzle "Failed query: ..." message,
6986
+ * keeping only the error description.
6987
+ */
6988
+ stripSqlFromMessage(message, collectionSlug) {
6989
+ if (message.startsWith("Failed query:")) {
6990
+ return `Failed to save entity in "${collectionSlug}". Check server logs for details.`;
6991
+ }
6992
+ return message;
6774
6993
  }
6775
6994
  /**
6776
6995
  * Extract the underlying PostgreSQL error from a Drizzle wrapper.
@@ -6779,7 +6998,7 @@ class EntityPersistService {
6779
6998
  extractPgError(error) {
6780
6999
  if (!error || typeof error !== "object") return null;
6781
7000
  const err = error;
6782
- if (err.code && /^[0-9]{5}$/.test(err.code)) {
7001
+ if (err.code && /^[0-9A-Z]{5}$/.test(err.code)) {
6783
7002
  return err;
6784
7003
  }
6785
7004
  if (err.cause && typeof err.cause === "object") {
@@ -7067,6 +7286,7 @@ class PostgresBackendDriver {
7067
7286
  branchService;
7068
7287
  user;
7069
7288
  data;
7289
+ client;
7070
7290
  /**
7071
7291
  * When true, realtime notifications are deferred until after the
7072
7292
  * wrapping transaction commits. Set by `withAuth` → `withTransaction`.
@@ -7095,6 +7315,14 @@ class PostgresBackendDriver {
7095
7315
  } : {}
7096
7316
  };
7097
7317
  }
7318
+ /**
7319
+ * REST-optimised fetch service (include-aware eager-loading).
7320
+ * Delegates to the underlying EntityFetchService which already
7321
+ * implements the matching method signatures.
7322
+ */
7323
+ get restFetchService() {
7324
+ return this.entityService.getFetchService();
7325
+ }
7098
7326
  resolveCollectionCallbacks(collection, path2) {
7099
7327
  if (!collection && !path2) return {
7100
7328
  collection: void 0,
@@ -7148,7 +7376,8 @@ class PostgresBackendDriver {
7148
7376
  const contextForCallback = {
7149
7377
  user: this.user,
7150
7378
  driver: this,
7151
- data: this.data
7379
+ data: this.data,
7380
+ client: this.client
7152
7381
  };
7153
7382
  return Promise.all(entities.map(async (entity) => {
7154
7383
  let fetched = entity;
@@ -7242,7 +7471,8 @@ class PostgresBackendDriver {
7242
7471
  const contextForCallback = {
7243
7472
  user: this.user,
7244
7473
  driver: this,
7245
- data: this.data
7474
+ data: this.data,
7475
+ client: this.client
7246
7476
  };
7247
7477
  if (callbacks?.afterRead) {
7248
7478
  entity = await callbacks.afterRead({
@@ -7311,7 +7541,8 @@ class PostgresBackendDriver {
7311
7541
  const contextForCallback = {
7312
7542
  user: this.user,
7313
7543
  driver: this,
7314
- data: this.data
7544
+ data: this.data,
7545
+ client: this.client
7315
7546
  };
7316
7547
  let previousValuesForHistory;
7317
7548
  if (status === "existing" && entityId) {
@@ -7346,6 +7577,14 @@ class PostgresBackendDriver {
7346
7577
  if (result) updatedValues = mergeDeep(updatedValues, result);
7347
7578
  }
7348
7579
  }
7580
+ if (resolvedCollection?.properties) {
7581
+ updatedValues = updateDateAutoValues({
7582
+ inputValues: updatedValues,
7583
+ properties: resolvedCollection.properties,
7584
+ status: status ?? "new",
7585
+ timestampNowValue: /* @__PURE__ */ new Date()
7586
+ });
7587
+ }
7349
7588
  try {
7350
7589
  let savedEntity = await this.entityService.saveEntity(path2, updatedValues, entityId, resolvedCollection?.databaseId);
7351
7590
  if (savedEntity && (callbacks?.afterRead || propertyCallbacks?.afterRead)) {
@@ -7451,7 +7690,8 @@ class PostgresBackendDriver {
7451
7690
  const contextForCallback = {
7452
7691
  user: this.user,
7453
7692
  driver: this,
7454
- data: this.data
7693
+ data: this.data,
7694
+ client: this.client
7455
7695
  };
7456
7696
  if (callbacks?.beforeDelete || propertyCallbacks?.beforeDelete) {
7457
7697
  if (callbacks?.beforeDelete) {
@@ -7778,6 +8018,7 @@ class AuthenticatedPostgresBackendDriver {
7778
8018
  txDelegate.entityService = txEntityService;
7779
8019
  txDelegate._deferNotifications = true;
7780
8020
  txDelegate._pendingNotifications = pendingNotifications;
8021
+ txDelegate.client = this.delegate.client;
7781
8022
  return await operation(txDelegate);
7782
8023
  });
7783
8024
  for (const notification of pendingNotifications) {
@@ -8059,6 +8300,12 @@ const userIdentitiesRelations = relations(userIdentities, ({
8059
8300
  references: [users.id]
8060
8301
  })
8061
8302
  }));
8303
+ const resolveColumnName = (propName, prop) => {
8304
+ if (prop && "columnName" in prop && typeof prop.columnName === "string") {
8305
+ return prop.columnName;
8306
+ }
8307
+ return toSnakeCase(propName);
8308
+ };
8062
8309
  const getPrimaryKeyProp = (collection) => {
8063
8310
  if (collection.properties) {
8064
8311
  const idPropEntry = Object.entries(collection.properties).find(([_, prop]) => "isId" in prop && Boolean(prop.isId));
@@ -8099,7 +8346,7 @@ const isIdProperty = (propName, prop, collection) => {
8099
8346
  return !hasExplicitId && propName === "id";
8100
8347
  };
8101
8348
  const getDrizzleColumn = (propName, prop, collection, collections) => {
8102
- const colName = toSnakeCase(propName);
8349
+ const colName = resolveColumnName(propName, prop);
8103
8350
  let columnDefinition;
8104
8351
  switch (prop.type) {
8105
8352
  case "string": {
@@ -8171,6 +8418,9 @@ const getDrizzleColumn = (propName, prop, collection, collections) => {
8171
8418
  } else {
8172
8419
  columnDefinition = `timestamp("${colName}", { withTimezone: true, mode: 'string' })`;
8173
8420
  }
8421
+ if (dateProp.autoValue === "on_create" || dateProp.autoValue === "on_update") {
8422
+ columnDefinition += `.default(sql\`now()\`)`;
8423
+ }
8174
8424
  break;
8175
8425
  }
8176
8426
  case "map":
@@ -8203,7 +8453,7 @@ const getDrizzleColumn = (propName, prop, collection, collections) => {
8203
8453
  } catch {
8204
8454
  return null;
8205
8455
  }
8206
- const fkColumnName = toSnakeCase(relation.localKey);
8456
+ const fkColumnName = relation.localKey;
8207
8457
  const targetTableVar = getTableVarName(getTableName(targetCollection));
8208
8458
  const pkProp = getPrimaryKeyProp(targetCollection);
8209
8459
  const targetIdField = pkProp.name;
@@ -8391,7 +8641,7 @@ const generateSchema = async (collections, stripPolicies = false) => {
8391
8641
  Object.entries(collection.properties ?? {}).forEach(([propName, prop]) => {
8392
8642
  if ("enum" in prop && (prop.type === "string" || prop.type === "number") && prop.enum) {
8393
8643
  const enumVarName = getEnumVarName(collectionPath, propName);
8394
- const enumDbName = `${collectionPath}_${toSnakeCase(propName)}`;
8644
+ const enumDbName = `${collectionPath}_${resolveColumnName(propName, prop)}`;
8395
8645
  const values = Array.isArray(prop.enum) ? prop.enum.map((v) => String(v.id ?? v)) : Object.keys(prop.enum);
8396
8646
  if (values.length > 0) {
8397
8647
  schemaContent += `export const ${enumVarName} = pgEnum("${enumDbName}", [${values.map((v) => `'${v}'`).join(", ")}]);
@@ -8448,9 +8698,9 @@ const generateSchema = async (collections, stripPolicies = false) => {
8448
8698
  const targetId = getPrimaryKeyName(targetCollection);
8449
8699
  schemaContent += `export const ${tableVarName} = pgTable("${tableName}", {
8450
8700
  `;
8451
- schemaContent += ` ${sourceColumn}: ${sourceColType}("${toSnakeCase(sourceColumn)}").notNull().references(() => ${getTableVarName(getTableName(sourceCollection))}.${sourceId}, ${refOptions}),
8701
+ schemaContent += ` ${sourceColumn}: ${sourceColType}("${sourceColumn}").notNull().references(() => ${getTableVarName(getTableName(sourceCollection))}.${sourceId}, ${refOptions}),
8452
8702
  `;
8453
- schemaContent += ` ${targetColumn}: ${targetColType}("${toSnakeCase(targetColumn)}").notNull().references(() => ${getTableVarName(getTableName(targetCollection))}.${targetId}, ${refOptions}),
8703
+ schemaContent += ` ${targetColumn}: ${targetColType}("${targetColumn}").notNull().references(() => ${getTableVarName(getTableName(targetCollection))}.${targetId}, ${refOptions}),
8454
8704
  `;
8455
8705
  schemaContent += "}, (table) => ({\n";
8456
8706
  schemaContent += ` pk: primaryKey({ columns: [table.${sourceColumn}, table.${targetColumn}] })
@@ -8543,29 +8793,10 @@ const generateSchema = async (collections, stripPolicies = false) => {
8543
8793
  references: [${targetTableVar}.${getPrimaryKeyName(target)}],
8544
8794
  relationName: "${drizzleRelationName}"
8545
8795
  })`);
8546
- } else if (rel.direction === "inverse" && rel.foreignKeyOnTarget) {
8547
- const sourceIdField = getPrimaryKeyName(collection);
8796
+ } else if (rel.direction === "inverse") {
8548
8797
  tableRelations.push(` "${relationKey}": one(${targetTableVar}, {
8549
- fields: [${tableVarName}.${sourceIdField}],
8550
- references: [${targetTableVar}.${rel.foreignKeyOnTarget}],
8551
8798
  relationName: "${drizzleRelationName}"
8552
8799
  })`);
8553
- } else if (rel.direction === "inverse" && !rel.foreignKeyOnTarget) {
8554
- try {
8555
- const targetCollection = rel.target();
8556
- const targetResolvedRelations = resolveCollectionRelations(targetCollection);
8557
- const correspondingRelation = Object.values(targetResolvedRelations).find((targetRel) => targetRel.direction === "owning" && targetRel.cardinality === "one" && targetRel.target().slug === collection.slug);
8558
- if (correspondingRelation && correspondingRelation.localKey) {
8559
- const sourceIdField = getPrimaryKeyName(collection);
8560
- tableRelations.push(` "${relationKey}": one(${targetTableVar}, {
8561
- fields: [${tableVarName}.${sourceIdField}],
8562
- references: [${targetTableVar}.${correspondingRelation.localKey}],
8563
- relationName: "${drizzleRelationName}"
8564
- })`);
8565
- }
8566
- } catch (e) {
8567
- console.warn(`Could not resolve inverse one-to-one relation '${relationKey}':`, e);
8568
- }
8569
8800
  }
8570
8801
  } else if (rel.cardinality === "many") {
8571
8802
  if (rel.direction === "inverse" && rel.foreignKeyOnTarget) {
@@ -8593,6 +8824,32 @@ const generateSchema = async (collections, stripPolicies = false) => {
8593
8824
  console.warn(`Could not generate relation ${relationKey} for ${collection.name}:`, e);
8594
8825
  }
8595
8826
  }
8827
+ for (const otherCollection of collections) {
8828
+ if (otherCollection.slug === collection.slug) continue;
8829
+ const otherRelations = resolveCollectionRelations(otherCollection);
8830
+ for (const [otherKey, otherRel] of Object.entries(otherRelations)) {
8831
+ if (otherRel.direction === "inverse" && otherRel.foreignKeyOnTarget) {
8832
+ try {
8833
+ const otherTarget = otherRel.target();
8834
+ if (otherTarget.slug === collection.slug) {
8835
+ const drizzleRelationName = computeSharedRelationName(otherRel, otherCollection, collections);
8836
+ const deduplicationKey = `${drizzleRelationName}::owning`;
8837
+ if (!emittedRelationNames.has(deduplicationKey)) {
8838
+ const otherTableVar = getTableVarName(getTableName(otherCollection));
8839
+ const synthKey = `_synth_${otherTableVar}_${otherRel.foreignKeyOnTarget}`;
8840
+ tableRelations.push(` "${synthKey}": one(${otherTableVar}, {
8841
+ fields: [${tableVarName}.${otherRel.foreignKeyOnTarget}],
8842
+ references: [${otherTableVar}.${getPrimaryKeyName(otherCollection)}],
8843
+ relationName: "${drizzleRelationName}"
8844
+ })`);
8845
+ emittedRelationNames.add(deduplicationKey);
8846
+ }
8847
+ }
8848
+ } catch (e) {
8849
+ }
8850
+ }
8851
+ }
8852
+ }
8596
8853
  }
8597
8854
  if (tableRelations.length > 0) {
8598
8855
  const relVarName = `${tableVarName}Relations`;