@arcote.tech/arc-adapter-db-postgres 0.7.27 → 0.7.28

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 (2) hide show
  1. package/dist/index.js +180 -33
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -1829,9 +1829,12 @@ class LocalEventPublisher {
1829
1829
  store: EVENT_TABLES.events,
1830
1830
  changes: [{ type: "set", data: storedEvent }]
1831
1831
  });
1832
- if (event.payload && typeof event.payload === "object") {
1832
+ const tagFields = event.definition?.tagFields ?? [];
1833
+ if (tagFields.length > 0 && event.payload && typeof event.payload === "object") {
1834
+ const payload = event.payload;
1833
1835
  const tagChanges = [];
1834
- for (const [key, value] of Object.entries(event.payload)) {
1836
+ for (const key of tagFields) {
1837
+ const value = payload[key];
1835
1838
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1836
1839
  tagChanges.push({
1837
1840
  type: "set",
@@ -2055,6 +2058,11 @@ class ArcOptional {
2055
2058
  return false;
2056
2059
  return this.parent.validate(value);
2057
2060
  }
2061
+ coerce(value) {
2062
+ if (value == null)
2063
+ return;
2064
+ return this.parent.coerce(value);
2065
+ }
2058
2066
  toJsonSchema() {
2059
2067
  const parentSchema = this.parent.toJsonSchema?.() ?? {};
2060
2068
  return {
@@ -2101,6 +2109,9 @@ class ArcBranded {
2101
2109
  validate(value) {
2102
2110
  return this.parent.validate(value);
2103
2111
  }
2112
+ coerce(value) {
2113
+ return this.parent.coerce(value);
2114
+ }
2104
2115
  toJsonSchema() {
2105
2116
  return this.parent.toJsonSchema?.() ?? {};
2106
2117
  }
@@ -2125,6 +2136,11 @@ class ArcDefault {
2125
2136
  return false;
2126
2137
  return this.parent.validate(value);
2127
2138
  }
2139
+ coerce(value) {
2140
+ if (value === undefined || value === null)
2141
+ return;
2142
+ return this.parent.coerce(value);
2143
+ }
2128
2144
  parse(value) {
2129
2145
  if (value)
2130
2146
  return this.parent.parse(value);
@@ -2207,6 +2223,9 @@ class ArcAbstract {
2207
2223
  }
2208
2224
  return false;
2209
2225
  }
2226
+ coerce(value) {
2227
+ return this.validate(value) ? undefined : value;
2228
+ }
2210
2229
  pipeValidation(name, validator) {
2211
2230
  const newInstance = this.clone();
2212
2231
  newInstance.validations = [...this.validations, { name, validator }];
@@ -2344,6 +2363,17 @@ class ArcArray extends ArcAbstract {
2344
2363
  return { msg: "array is empty" };
2345
2364
  });
2346
2365
  }
2366
+ coerce(value) {
2367
+ if (!Array.isArray(value))
2368
+ return;
2369
+ const out = [];
2370
+ for (const item of value) {
2371
+ const coerced = this.parent.coerce(item);
2372
+ if (coerced !== undefined)
2373
+ out.push(coerced);
2374
+ }
2375
+ return this.validate(out) ? undefined : out;
2376
+ }
2347
2377
  parse(value) {
2348
2378
  return value.map((v) => this.parent.parse(v));
2349
2379
  }
@@ -2415,6 +2445,19 @@ class ArcObject extends ArcAbstract {
2415
2445
  ]);
2416
2446
  this.rawShape = rawShape;
2417
2447
  }
2448
+ coerce(value) {
2449
+ if (value == null || typeof value !== "object" || Array.isArray(value)) {
2450
+ return;
2451
+ }
2452
+ const src = value;
2453
+ const out = {};
2454
+ for (const [key, element] of Object.entries(this.rawShape)) {
2455
+ const coerced = element.coerce(src[key]);
2456
+ if (coerced !== undefined)
2457
+ out[key] = coerced;
2458
+ }
2459
+ return this.validate(out) ? undefined : out;
2460
+ }
2418
2461
  parse(value) {
2419
2462
  return Object.entries(this.rawShape).reduce((acc, [key, element]) => {
2420
2463
  acc[key] = element.parse(value[key]);
@@ -2664,6 +2707,25 @@ class ArcAuthorizationError extends Error {
2664
2707
  this.name = "ArcAuthorizationError";
2665
2708
  }
2666
2709
  }
2710
+ function collectFieldPaths(errors, prefix = "") {
2711
+ if (!errors || typeof errors !== "object")
2712
+ return [];
2713
+ const schema = errors.schema;
2714
+ if (!schema || typeof schema !== "object")
2715
+ return [];
2716
+ const out = [];
2717
+ for (const [field, fieldError] of Object.entries(schema)) {
2718
+ if (!fieldError)
2719
+ continue;
2720
+ const path = prefix ? `${prefix}.${field}` : field;
2721
+ const nested = collectFieldPaths(fieldError, path);
2722
+ if (nested.length > 0)
2723
+ out.push(...nested);
2724
+ else
2725
+ out.push(path);
2726
+ }
2727
+ return out;
2728
+ }
2667
2729
 
2668
2730
  class ArcValidationError extends Error {
2669
2731
  arcCode = "VALIDATION";
@@ -2671,7 +2733,8 @@ class ArcValidationError extends Error {
2671
2733
  constructor(errors, message = "Invalid parameters") {
2672
2734
  super(message);
2673
2735
  this.name = "ArcValidationError";
2674
- this.fields = errors && typeof errors === "object" ? Object.keys(errors) : [];
2736
+ const paths = collectFieldPaths(errors);
2737
+ this.fields = paths.length > 0 ? paths : errors && typeof errors === "object" ? Object.keys(errors) : [];
2675
2738
  }
2676
2739
  }
2677
2740
  class ArcPrimitive extends ArcAbstract {
@@ -3038,7 +3101,8 @@ class ArcEvent extends ArcContextElement {
3038
3101
  payload,
3039
3102
  id: this.eventId.generate(),
3040
3103
  createdAt: new Date,
3041
- authContext
3104
+ authContext,
3105
+ definition: this
3042
3106
  };
3043
3107
  await adapters.eventPublisher.publish(event);
3044
3108
  }
@@ -3091,8 +3155,8 @@ class ArcEvent extends ArcContextElement {
3091
3155
  const tagsSchema = new ArcObject({
3092
3156
  _id: new ArcString().primaryKey(),
3093
3157
  eventId: new ArcString().index(),
3094
- tagKey: new ArcString().index(),
3095
- tagValue: new ArcString().index()
3158
+ tagKey: new ArcString,
3159
+ tagValue: new ArcString
3096
3160
  });
3097
3161
  const syncStatusSchema = new ArcObject({
3098
3162
  _id: new ArcString().primaryKey(),
@@ -4033,16 +4097,57 @@ function resolveQueryChange(currentResult, event3, options) {
4033
4097
  }
4034
4098
  const shouldBeInResult = checkItemMatchesWhere(event3.item, options.where);
4035
4099
  if (isInCurrentResult && shouldBeInResult) {
4036
- const newResult = currentResult.toSpliced(index, 1, event3.item);
4037
- return applyOrderByAndLimit(newResult, options);
4100
+ if (!options.orderBy) {
4101
+ return applyLimit(currentResult.toSpliced(index, 1, event3.item), options);
4102
+ }
4103
+ const cmp = compareByOrderBy(options.orderBy);
4104
+ if (cmp(currentResult[index], event3.item) === 0) {
4105
+ return applyLimit(currentResult.toSpliced(index, 1, event3.item), options);
4106
+ }
4107
+ const without = currentResult.toSpliced(index, 1);
4108
+ const at = upperBound(without, event3.item, cmp);
4109
+ return applyLimit(without.toSpliced(at, 0, event3.item), options);
4038
4110
  } else if (isInCurrentResult && !shouldBeInResult) {
4039
4111
  return currentResult.toSpliced(index, 1);
4040
4112
  } else if (!isInCurrentResult && shouldBeInResult) {
4041
- const newResult = [...currentResult, event3.item];
4042
- return applyOrderByAndLimit(newResult, options);
4113
+ if (!options.orderBy) {
4114
+ return applyLimit([...currentResult, event3.item], options);
4115
+ }
4116
+ const cmp = compareByOrderBy(options.orderBy);
4117
+ const at = upperBound(currentResult, event3.item, cmp);
4118
+ return applyLimit(currentResult.toSpliced(at, 0, event3.item), options);
4043
4119
  }
4044
4120
  return false;
4045
4121
  }
4122
+ function compareByOrderBy(orderBy) {
4123
+ const entries = Object.entries(orderBy);
4124
+ return (a, b) => {
4125
+ for (const [key, direction] of entries) {
4126
+ const aVal = a[key];
4127
+ const bVal = b[key];
4128
+ if (aVal < bVal)
4129
+ return direction === "asc" ? -1 : 1;
4130
+ if (aVal > bVal)
4131
+ return direction === "asc" ? 1 : -1;
4132
+ }
4133
+ return 0;
4134
+ };
4135
+ }
4136
+ function upperBound(arr, item, cmp) {
4137
+ let lo = 0;
4138
+ let hi = arr.length;
4139
+ while (lo < hi) {
4140
+ const mid = lo + hi >> 1;
4141
+ if (cmp(arr[mid], item) <= 0)
4142
+ lo = mid + 1;
4143
+ else
4144
+ hi = mid;
4145
+ }
4146
+ return lo;
4147
+ }
4148
+ function applyLimit(result, options) {
4149
+ return options.limit !== undefined && result.length > options.limit ? result.slice(0, options.limit) : result;
4150
+ }
4046
4151
  function checkItemMatchesWhere(item, where) {
4047
4152
  if (!where) {
4048
4153
  return true;
@@ -4078,27 +4183,6 @@ function checkItemMatchesWhere(item, where) {
4078
4183
  });
4079
4184
  });
4080
4185
  }
4081
- function applyOrderByAndLimit(result, options) {
4082
- let sorted = result;
4083
- if (options.orderBy) {
4084
- sorted = [...result].sort((a, b) => {
4085
- for (const [key, direction] of Object.entries(options.orderBy)) {
4086
- const aVal = a[key];
4087
- const bVal = b[key];
4088
- if (aVal < bVal)
4089
- return direction === "asc" ? -1 : 1;
4090
- if (aVal > bVal)
4091
- return direction === "asc" ? 1 : -1;
4092
- }
4093
- return 0;
4094
- });
4095
- }
4096
- if (options.limit !== undefined) {
4097
- sorted = sorted.slice(0, options.limit);
4098
- }
4099
- return sorted;
4100
- }
4101
-
4102
4186
  class ObservableDataStorage {
4103
4187
  source;
4104
4188
  onChange;
@@ -6817,6 +6901,40 @@ function osUsername() {
6817
6901
  }
6818
6902
 
6819
6903
  // src/postgres-adapter.ts
6904
+ var MAX_SAFE_INT = BigInt(Number.MAX_SAFE_INTEGER);
6905
+ var MIN_SAFE_INT = BigInt(Number.MIN_SAFE_INTEGER);
6906
+ function unsafeIntMessage(raw, columnName) {
6907
+ const where = columnName ? ` w kolumnie "${columnName}"` : "";
6908
+ return `[PostgreSQL] Wartość całkowita ${raw}${where} przekracza bezpieczny zakres ` + `JS Number (±2^53-1). Odczyt jako number cicho straciłby precyzję. ` + `Użyj kolumny TEXT/NUMERIC i obsłuż wartość jako string/BigInt.`;
6909
+ }
6910
+ function coercePgNumber(value, columnName) {
6911
+ if (value === null || value === undefined)
6912
+ return value;
6913
+ if (typeof value === "number")
6914
+ return value;
6915
+ if (typeof value === "bigint") {
6916
+ if (value > MAX_SAFE_INT || value < MIN_SAFE_INT) {
6917
+ throw new Error(unsafeIntMessage(value.toString(), columnName));
6918
+ }
6919
+ return Number(value);
6920
+ }
6921
+ if (typeof value === "string") {
6922
+ const s = value.trim();
6923
+ if (s === "")
6924
+ return value;
6925
+ if (/^[+-]?\d+$/.test(s)) {
6926
+ const big = BigInt(s);
6927
+ if (big > MAX_SAFE_INT || big < MIN_SAFE_INT) {
6928
+ throw new Error(unsafeIntMessage(s, columnName));
6929
+ }
6930
+ return Number(big);
6931
+ }
6932
+ const n = Number(s);
6933
+ return Number.isNaN(n) ? value : n;
6934
+ }
6935
+ return value;
6936
+ }
6937
+
6820
6938
  class PostgreSQLReadTransaction {
6821
6939
  db;
6822
6940
  tables;
@@ -6838,7 +6956,27 @@ class PostgreSQLReadTransaction {
6838
6956
  deserializeValue(value, column) {
6839
6957
  if (value === null || value === undefined)
6840
6958
  return null;
6841
- switch (column.type.toLowerCase()) {
6959
+ const type = column.type.toLowerCase().split("(")[0].trim();
6960
+ switch (type) {
6961
+ case "bigint":
6962
+ case "int8":
6963
+ case "bigserial":
6964
+ case "serial8":
6965
+ case "serial":
6966
+ case "serial4":
6967
+ case "integer":
6968
+ case "int":
6969
+ case "int4":
6970
+ case "smallint":
6971
+ case "int2":
6972
+ case "numeric":
6973
+ case "decimal":
6974
+ case "real":
6975
+ case "double precision":
6976
+ case "float":
6977
+ case "float4":
6978
+ case "float8":
6979
+ return coercePgNumber(value, column.name);
6842
6980
  case "json":
6843
6981
  case "jsonb":
6844
6982
  if (typeof value === "string") {
@@ -7489,7 +7627,15 @@ class PostgresJsDatabase {
7489
7627
  }
7490
7628
  var createPostgreSQLAdapterFactoryFromUrl = (connectionString) => {
7491
7629
  const sql = src_default(connectionString, {
7492
- onnotice: () => {}
7630
+ onnotice: () => {},
7631
+ types: {
7632
+ bigint: {
7633
+ to: 20,
7634
+ from: [20],
7635
+ serialize: (v) => v.toString(),
7636
+ parse: (v) => coercePgNumber(v)
7637
+ }
7638
+ }
7493
7639
  });
7494
7640
  const db = new PostgresJsDatabase(sql);
7495
7641
  return createPostgreSQLAdapterFactory(db);
@@ -7497,5 +7643,6 @@ var createPostgreSQLAdapterFactoryFromUrl = (connectionString) => {
7497
7643
  export {
7498
7644
  createPostgreSQLAdapterFactoryFromUrl,
7499
7645
  createPostgreSQLAdapterFactory,
7646
+ coercePgNumber,
7500
7647
  PostgreSQLAdapter
7501
7648
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcote.tech/arc-adapter-db-postgres",
3
- "version": "0.7.27",
3
+ "version": "0.7.28",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -23,7 +23,7 @@
23
23
  "postgres": "^3.4.4"
24
24
  },
25
25
  "peerDependencies": {
26
- "@arcote.tech/arc": "^0.7.27"
26
+ "@arcote.tech/arc": "^0.7.28"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/pg": "^8.11.0",