@atscript/db-mongo 0.1.88 → 0.1.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -919,16 +919,20 @@ async function syncColumnsImpl(host, diff) {
919
919
  if (diff.renamed.length > 0) {
920
920
  const renameSpec = {};
921
921
  for (const r of diff.renamed) {
922
+ if (pathCrossesArray(host, r.field.path)) {
923
+ host._log("syncColumns: skipping $rename for array-element field", r.oldName, "→", r.field.physicalName, "(Mongo $rename cannot traverse arrays)");
924
+ continue;
925
+ }
922
926
  renameSpec[r.oldName] = r.field.physicalName;
923
927
  renamed.push(r.field.physicalName);
924
928
  }
925
- update.$rename = renameSpec;
929
+ if (Object.keys(renameSpec).length > 0) update.$rename = renameSpec;
926
930
  }
927
931
  if (diff.added.length > 0) {
928
932
  const setSpec = {};
929
933
  for (const field of diff.added) {
930
934
  const defaultVal = resolveSyncDefault(field);
931
- if (defaultVal !== void 0) setSpec[field.physicalName] = defaultVal;
935
+ if (defaultVal !== void 0) setSpec[arraySafePath(host, field.physicalName, field.path)] = defaultVal;
932
936
  added.push(field.physicalName);
933
937
  }
934
938
  if (Object.keys(setSpec).length > 0) update.$set = setSpec;
@@ -942,13 +946,52 @@ async function syncColumnsImpl(host, diff) {
942
946
  async function dropColumnsImpl(host, columns) {
943
947
  if (columns.length === 0) return;
944
948
  const unsetSpec = {};
945
- for (const col of columns) unsetSpec[col] = "";
949
+ for (const col of columns) unsetSpec[arraySafePath(host, col, col)] = "";
946
950
  await host.collection.updateMany({}, { $unset: unsetSpec }, host._getSessionOpts());
947
951
  }
952
+ /**
953
+ * Rewrites a dotted physical path to use Mongo's all-positional $[] operator
954
+ * at every segment that's typed as an array in the table's flatMap. Returns
955
+ * the input unchanged when no segment crosses an array boundary.
956
+ *
957
+ * `logicalPath` drives the array-boundary walk (flatMap is keyed by logical
958
+ * path); the leaf of `physicalPath` is preserved so any `@db.column` rename
959
+ * on the leaf still applies.
960
+ */
961
+ function arraySafePath(host, physicalPath, logicalPath) {
962
+ const logicalSegments = logicalPath.split(".");
963
+ if (logicalSegments.length < 2) return physicalPath;
964
+ const physicalSegments = physicalPath.split(".");
965
+ const physicalLeaf = physicalSegments[physicalSegments.length - 1];
966
+ const out = [];
967
+ let prefix = "";
968
+ for (let i = 0; i < logicalSegments.length; i++) {
969
+ const isLeaf = i === logicalSegments.length - 1;
970
+ out.push(isLeaf ? physicalLeaf : logicalSegments[i]);
971
+ prefix = prefix ? `${prefix}.${logicalSegments[i]}` : logicalSegments[i];
972
+ if (!isLeaf) {
973
+ const type = host._table.flatMap.get(prefix);
974
+ if (type && (0, _atscript_db.resolveDesignType)(type) === "array") out.push("$[]");
975
+ }
976
+ }
977
+ return out.join(".");
978
+ }
979
+ /** Returns true if any non-leaf segment of the path is typed as an array. */
980
+ function pathCrossesArray(host, logicalPath) {
981
+ const segments = logicalPath.split(".");
982
+ if (segments.length < 2) return false;
983
+ let prefix = "";
984
+ for (let i = 0; i < segments.length - 1; i++) {
985
+ prefix = prefix ? `${prefix}.${segments[i]}` : segments[i];
986
+ const type = host._table.flatMap.get(prefix);
987
+ if (type && (0, _atscript_db.resolveDesignType)(type) === "array") return true;
988
+ }
989
+ return false;
990
+ }
948
991
  /** Resolves a field's default value for bulk $set during column sync. */
949
992
  function resolveSyncDefault(field) {
950
- if (!field.defaultValue) return field.optional ? null : void 0;
951
- if (field.defaultValue.kind === "value") return field.defaultValue.value;
993
+ if (!field.defaultValue) return;
994
+ if (field.defaultValue.kind === "value") return field.designType === "string" ? field.defaultValue.value : JSON.parse(field.defaultValue.value);
952
995
  }
953
996
  async function syncIndexesImpl(host) {
954
997
  await host.ensureCollectionExists();
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { t as buildMongoFilter } from "./mongo-filter-BsocUQG3.mjs";
2
- import { AtscriptDbView, BaseDbAdapter, DbError, DbSpace, computeInsights, getDbFieldOp, getKeyProps } from "@atscript/db";
2
+ import { AtscriptDbView, BaseDbAdapter, DbError, DbSpace, computeInsights, getDbFieldOp, getKeyProps, resolveDesignType } from "@atscript/db";
3
3
  import { MongoClient, MongoServerError, ObjectId } from "mongodb";
4
4
  //#region src/lib/collection-patcher.ts
5
5
  /**
@@ -918,16 +918,20 @@ async function syncColumnsImpl(host, diff) {
918
918
  if (diff.renamed.length > 0) {
919
919
  const renameSpec = {};
920
920
  for (const r of diff.renamed) {
921
+ if (pathCrossesArray(host, r.field.path)) {
922
+ host._log("syncColumns: skipping $rename for array-element field", r.oldName, "→", r.field.physicalName, "(Mongo $rename cannot traverse arrays)");
923
+ continue;
924
+ }
921
925
  renameSpec[r.oldName] = r.field.physicalName;
922
926
  renamed.push(r.field.physicalName);
923
927
  }
924
- update.$rename = renameSpec;
928
+ if (Object.keys(renameSpec).length > 0) update.$rename = renameSpec;
925
929
  }
926
930
  if (diff.added.length > 0) {
927
931
  const setSpec = {};
928
932
  for (const field of diff.added) {
929
933
  const defaultVal = resolveSyncDefault(field);
930
- if (defaultVal !== void 0) setSpec[field.physicalName] = defaultVal;
934
+ if (defaultVal !== void 0) setSpec[arraySafePath(host, field.physicalName, field.path)] = defaultVal;
931
935
  added.push(field.physicalName);
932
936
  }
933
937
  if (Object.keys(setSpec).length > 0) update.$set = setSpec;
@@ -941,13 +945,52 @@ async function syncColumnsImpl(host, diff) {
941
945
  async function dropColumnsImpl(host, columns) {
942
946
  if (columns.length === 0) return;
943
947
  const unsetSpec = {};
944
- for (const col of columns) unsetSpec[col] = "";
948
+ for (const col of columns) unsetSpec[arraySafePath(host, col, col)] = "";
945
949
  await host.collection.updateMany({}, { $unset: unsetSpec }, host._getSessionOpts());
946
950
  }
951
+ /**
952
+ * Rewrites a dotted physical path to use Mongo's all-positional $[] operator
953
+ * at every segment that's typed as an array in the table's flatMap. Returns
954
+ * the input unchanged when no segment crosses an array boundary.
955
+ *
956
+ * `logicalPath` drives the array-boundary walk (flatMap is keyed by logical
957
+ * path); the leaf of `physicalPath` is preserved so any `@db.column` rename
958
+ * on the leaf still applies.
959
+ */
960
+ function arraySafePath(host, physicalPath, logicalPath) {
961
+ const logicalSegments = logicalPath.split(".");
962
+ if (logicalSegments.length < 2) return physicalPath;
963
+ const physicalSegments = physicalPath.split(".");
964
+ const physicalLeaf = physicalSegments[physicalSegments.length - 1];
965
+ const out = [];
966
+ let prefix = "";
967
+ for (let i = 0; i < logicalSegments.length; i++) {
968
+ const isLeaf = i === logicalSegments.length - 1;
969
+ out.push(isLeaf ? physicalLeaf : logicalSegments[i]);
970
+ prefix = prefix ? `${prefix}.${logicalSegments[i]}` : logicalSegments[i];
971
+ if (!isLeaf) {
972
+ const type = host._table.flatMap.get(prefix);
973
+ if (type && resolveDesignType(type) === "array") out.push("$[]");
974
+ }
975
+ }
976
+ return out.join(".");
977
+ }
978
+ /** Returns true if any non-leaf segment of the path is typed as an array. */
979
+ function pathCrossesArray(host, logicalPath) {
980
+ const segments = logicalPath.split(".");
981
+ if (segments.length < 2) return false;
982
+ let prefix = "";
983
+ for (let i = 0; i < segments.length - 1; i++) {
984
+ prefix = prefix ? `${prefix}.${segments[i]}` : segments[i];
985
+ const type = host._table.flatMap.get(prefix);
986
+ if (type && resolveDesignType(type) === "array") return true;
987
+ }
988
+ return false;
989
+ }
947
990
  /** Resolves a field's default value for bulk $set during column sync. */
948
991
  function resolveSyncDefault(field) {
949
- if (!field.defaultValue) return field.optional ? null : void 0;
950
- if (field.defaultValue.kind === "value") return field.defaultValue.value;
992
+ if (!field.defaultValue) return;
993
+ if (field.defaultValue.kind === "value") return field.designType === "string" ? field.defaultValue.value : JSON.parse(field.defaultValue.value);
951
994
  }
952
995
  async function syncIndexesImpl(host) {
953
996
  await host.ensureCollectionExists();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atscript/db-mongo",
3
- "version": "0.1.88",
3
+ "version": "0.1.89",
4
4
  "description": "Mongodb plugin for atscript.",
5
5
  "keywords": [
6
6
  "atscript",
@@ -46,17 +46,17 @@
46
46
  "access": "public"
47
47
  },
48
48
  "devDependencies": {
49
- "@atscript/core": "^0.1.62",
50
- "@atscript/typescript": "^0.1.62",
49
+ "@atscript/core": "^0.1.63",
50
+ "@atscript/typescript": "^0.1.63",
51
51
  "mongodb": "^6.17.0",
52
52
  "mongodb-memory-server-core": "^10.0.0",
53
- "unplugin-atscript": "^0.1.62"
53
+ "unplugin-atscript": "^0.1.63"
54
54
  },
55
55
  "peerDependencies": {
56
- "@atscript/core": "^0.1.62",
57
- "@atscript/typescript": "^0.1.62",
56
+ "@atscript/core": "^0.1.63",
57
+ "@atscript/typescript": "^0.1.63",
58
58
  "mongodb": "^6.17.0",
59
- "@atscript/db": "^0.1.88"
59
+ "@atscript/db": "^0.1.89"
60
60
  },
61
61
  "scripts": {
62
62
  "postinstall": "asc -f dts",