@atscript/db-mongo 0.1.38 → 0.1.40

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/README.md ADDED
@@ -0,0 +1,60 @@
1
+ <p align="center">
2
+ <img src="https://atscript.dev/logo.svg" alt="Atscript" width="120" />
3
+ </p>
4
+
5
+ <h1 align="center">@atscript/db-mongo</h1>
6
+
7
+ <p align="center">
8
+ <strong>Define your models once</strong> — get TypeScript types, runtime validation, and DB metadata from a single <code>.as</code> model.
9
+ </p>
10
+
11
+ <p align="center">
12
+ <a href="https://db.atscript.dev">Documentation</a> · <a href="https://db.atscript.dev/adapters/mongodb">MongoDB Adapter</a>
13
+ </p>
14
+
15
+ ---
16
+
17
+ MongoDB adapter for `@atscript/db`. Translates Atscript's portable query model into native MongoDB operations with support for Atlas Search, vector search, aggregation pipelines, capped collections, and the Convenient Transaction API.
18
+
19
+ Includes `MongoPlugin` for `@db.mongo.*` annotations and custom primitives (`mongo.objectId`, `mongo.vector`).
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ pnpm add @atscript/db-mongo mongodb
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ```typescript
30
+ import { DbSpace } from "@atscript/db";
31
+ import { MongoAdapter } from "@atscript/db-mongo";
32
+ import { MongoClient } from "mongodb";
33
+
34
+ const client = new MongoClient("mongodb://localhost:27017/myapp");
35
+ const db = new DbSpace(() => new MongoAdapter(client.db(), client));
36
+ const todos = db.getTable(TodoType);
37
+
38
+ await todos.insertOne({ title: "Hello", done: false });
39
+ ```
40
+
41
+ ## Features
42
+
43
+ - Full CRUD with native MongoDB operations
44
+ - Atlas Search: dynamic and static text indexes with analyzers and fuzzy matching
45
+ - Vector search via `@db.search.vector` with configurable dimensions and similarity
46
+ - Native relation loading via `$lookup` aggregation stages
47
+ - Aggregation pipeline support
48
+ - Array patch operations via `CollectionPatcher`
49
+ - Capped collections via `@db.mongo.capped`
50
+ - Auto-increment via atomic counter collection
51
+ - Convenient Transaction API with automatic retry
52
+
53
+ ## Documentation
54
+
55
+ - [MongoDB Adapter Guide](https://db.atscript.dev/adapters/mongodb)
56
+ - [Full Documentation](https://db.atscript.dev)
57
+
58
+ ## License
59
+
60
+ MIT
package/dist/agg.cjs CHANGED
@@ -1,59 +1,9 @@
1
- "use strict";
2
- //#region rolldown:runtime
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
- key = keys[i];
12
- if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
- get: ((k) => from[k]).bind(null, key),
14
- enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
- });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
- value: mod,
21
- enumerable: true
22
- }) : target, mod));
23
-
24
- //#endregion
25
- const __atscript_db_agg = __toESM(require("@atscript/db/agg"));
26
- const __atscript_db = __toESM(require("@atscript/db"));
27
-
28
- //#region packages/db-mongo/src/lib/mongo-filter.ts
29
- const EMPTY = {};
30
- const mongoVisitor = {
31
- comparison(field, op, value) {
32
- if (op === "$eq") return { [field]: value };
33
- return { [field]: { [op]: value } };
34
- },
35
- and(children) {
36
- if (children.length === 0) return EMPTY;
37
- if (children.length === 1) return children[0];
38
- return { $and: children };
39
- },
40
- or(children) {
41
- if (children.length === 0) return { _impossible: true };
42
- if (children.length === 1) return children[0];
43
- return { $or: children };
44
- },
45
- not(child) {
46
- return { $nor: [child] };
47
- }
48
- };
49
- function buildMongoFilter(filter) {
50
- if (!filter || Object.keys(filter).length === 0) return EMPTY;
51
- return (0, __atscript_db.walkFilter)(filter, mongoVisitor) ?? EMPTY;
52
- }
53
-
54
- //#endregion
55
- //#region packages/db-mongo/src/agg.ts
56
- /** Simple accumulators that map directly to `{ $<fn>: '$field' }`. */ const SIMPLE_ACCUMULATORS = {
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_mongo_filter = require("./mongo-filter-B5ZINZPF.cjs");
3
+ let _atscript_db_agg = require("@atscript/db/agg");
4
+ //#region src/agg.ts
5
+ /** Simple accumulators that map directly to `{ $<fn>: '$field' }`. */
6
+ const SIMPLE_ACCUMULATORS = {
57
7
  sum: "$sum",
58
8
  avg: "$avg",
59
9
  min: "$min",
@@ -61,7 +11,8 @@ function buildMongoFilter(filter) {
61
11
  };
62
12
  /**
63
13
  * Maps an AggregateExpr to a MongoDB $group accumulator expression.
64
- */ function toAccumulator(expr) {
14
+ */
15
+ function toAccumulator(expr) {
65
16
  const simple = SIMPLE_ACCUMULATORS[expr.$fn];
66
17
  if (simple) return { [simple]: `$${expr.$field}` };
67
18
  if (expr.$fn === "count") {
@@ -77,10 +28,11 @@ function buildMongoFilter(filter) {
77
28
  /**
78
29
  * Builds the common prefix stages: $match + $group._id from groupBy fields.
79
30
  * Shared by both full aggregate and count pipelines.
80
- */ function buildPrefix(query) {
31
+ */
32
+ function buildPrefix(query) {
81
33
  const controls = query.controls || {};
82
34
  const groupBy = controls.$groupBy ?? [];
83
- const pipeline = [{ $match: buildMongoFilter(query.filter) }];
35
+ const pipeline = [{ $match: require_mongo_filter.buildMongoFilter(query.filter) }];
84
36
  const groupId = {};
85
37
  for (const field of groupBy) groupId[field] = `$${field}`;
86
38
  return {
@@ -90,6 +42,11 @@ function buildMongoFilter(filter) {
90
42
  controls
91
43
  };
92
44
  }
45
+ /**
46
+ * Builds a full MongoDB aggregation pipeline for GROUP BY queries.
47
+ *
48
+ * Pipeline: $match → $group → $project → $match(having) → $sort → $skip → $limit
49
+ */
93
50
  function buildAggregatePipeline(query) {
94
51
  const { pipeline, groupId, groupBy, controls } = buildPrefix(query);
95
52
  const groupStage = { _id: groupId };
@@ -97,18 +54,23 @@ function buildAggregatePipeline(query) {
97
54
  const aggregates = controls.$select?.aggregates;
98
55
  for (const field of groupBy) project[field] = `$_id.${field}`;
99
56
  if (aggregates) for (const expr of aggregates) {
100
- const alias = (0, __atscript_db_agg.resolveAlias)(expr);
57
+ const alias = (0, _atscript_db_agg.resolveAlias)(expr);
101
58
  groupStage[alias] = toAccumulator(expr);
102
59
  project[alias] = 1;
103
60
  }
104
61
  pipeline.push({ $group: groupStage });
105
62
  pipeline.push({ $project: project });
106
- if (controls.$having) pipeline.push({ $match: buildMongoFilter(controls.$having) });
63
+ if (controls.$having) pipeline.push({ $match: require_mongo_filter.buildMongoFilter(controls.$having) });
107
64
  if (controls.$sort) pipeline.push({ $sort: controls.$sort });
108
65
  if (controls.$skip) pipeline.push({ $skip: controls.$skip });
109
66
  if (controls.$limit) pipeline.push({ $limit: controls.$limit });
110
67
  return pipeline;
111
68
  }
69
+ /**
70
+ * Builds a count-only pipeline: returns the number of distinct groups.
71
+ *
72
+ * Pipeline: $match → $group (just _id) → $project → $match(having) → $count
73
+ */
112
74
  function buildCountPipeline(query) {
113
75
  const { pipeline, groupId, groupBy, controls } = buildPrefix(query);
114
76
  pipeline.push({ $group: { _id: groupId } });
@@ -116,12 +78,11 @@ function buildCountPipeline(query) {
116
78
  const project = { _id: 0 };
117
79
  for (const field of groupBy) project[field] = `$_id.${field}`;
118
80
  pipeline.push({ $project: project });
119
- pipeline.push({ $match: buildMongoFilter(controls.$having) });
81
+ pipeline.push({ $match: require_mongo_filter.buildMongoFilter(controls.$having) });
120
82
  }
121
83
  pipeline.push({ $count: "count" });
122
84
  return pipeline;
123
85
  }
124
-
125
86
  //#endregion
126
- exports.buildAggregatePipeline = buildAggregatePipeline
127
- exports.buildCountPipeline = buildCountPipeline
87
+ exports.buildAggregatePipeline = buildAggregatePipeline;
88
+ exports.buildCountPipeline = buildCountPipeline;
@@ -1,14 +1,7 @@
1
- import { DbQuery } from '@atscript/db';
2
- import { Document } from 'mongodb';
3
-
4
- /**
5
- * MongoDB aggregation pipeline builder.
6
- * Dynamically imported by MongoAdapter.aggregate() on first call.
7
- *
8
- * Constructs MongoDB aggregation pipelines from translated DbQuery objects
9
- * containing $groupBy, $select (with AggregateExpr), $having, $sort, etc.
10
- */
1
+ import { DbQuery } from "@atscript/db";
2
+ import { Document } from "mongodb";
11
3
 
4
+ //#region src/agg.d.ts
12
5
  /**
13
6
  * Builds a full MongoDB aggregation pipeline for GROUP BY queries.
14
7
  *
@@ -21,5 +14,5 @@ declare function buildAggregatePipeline(query: DbQuery): Document[];
21
14
  * Pipeline: $match → $group (just _id) → $project → $match(having) → $count
22
15
  */
23
16
  declare function buildCountPipeline(query: DbQuery): Document[];
24
-
25
- export { buildAggregatePipeline, buildCountPipeline };
17
+ //#endregion
18
+ export { buildAggregatePipeline, buildCountPipeline };
package/dist/agg.d.mts ADDED
@@ -0,0 +1,18 @@
1
+ import { DbQuery } from "@atscript/db";
2
+ import { Document } from "mongodb";
3
+
4
+ //#region src/agg.d.ts
5
+ /**
6
+ * Builds a full MongoDB aggregation pipeline for GROUP BY queries.
7
+ *
8
+ * Pipeline: $match → $group → $project → $match(having) → $sort → $skip → $limit
9
+ */
10
+ declare function buildAggregatePipeline(query: DbQuery): Document[];
11
+ /**
12
+ * Builds a count-only pipeline: returns the number of distinct groups.
13
+ *
14
+ * Pipeline: $match → $group (just _id) → $project → $match(having) → $count
15
+ */
16
+ declare function buildCountPipeline(query: DbQuery): Document[];
17
+ //#endregion
18
+ export { buildAggregatePipeline, buildCountPipeline };
package/dist/agg.mjs CHANGED
@@ -1,35 +1,8 @@
1
+ import { t as buildMongoFilter } from "./mongo-filter-CcQO-sEh.mjs";
1
2
  import { resolveAlias } from "@atscript/db/agg";
2
- import { walkFilter } from "@atscript/db";
3
-
4
- //#region packages/db-mongo/src/lib/mongo-filter.ts
5
- const EMPTY = {};
6
- const mongoVisitor = {
7
- comparison(field, op, value) {
8
- if (op === "$eq") return { [field]: value };
9
- return { [field]: { [op]: value } };
10
- },
11
- and(children) {
12
- if (children.length === 0) return EMPTY;
13
- if (children.length === 1) return children[0];
14
- return { $and: children };
15
- },
16
- or(children) {
17
- if (children.length === 0) return { _impossible: true };
18
- if (children.length === 1) return children[0];
19
- return { $or: children };
20
- },
21
- not(child) {
22
- return { $nor: [child] };
23
- }
24
- };
25
- function buildMongoFilter(filter) {
26
- if (!filter || Object.keys(filter).length === 0) return EMPTY;
27
- return walkFilter(filter, mongoVisitor) ?? EMPTY;
28
- }
29
-
30
- //#endregion
31
- //#region packages/db-mongo/src/agg.ts
32
- /** Simple accumulators that map directly to `{ $<fn>: '$field' }`. */ const SIMPLE_ACCUMULATORS = {
3
+ //#region src/agg.ts
4
+ /** Simple accumulators that map directly to `{ $<fn>: '$field' }`. */
5
+ const SIMPLE_ACCUMULATORS = {
33
6
  sum: "$sum",
34
7
  avg: "$avg",
35
8
  min: "$min",
@@ -37,7 +10,8 @@ function buildMongoFilter(filter) {
37
10
  };
38
11
  /**
39
12
  * Maps an AggregateExpr to a MongoDB $group accumulator expression.
40
- */ function toAccumulator(expr) {
13
+ */
14
+ function toAccumulator(expr) {
41
15
  const simple = SIMPLE_ACCUMULATORS[expr.$fn];
42
16
  if (simple) return { [simple]: `$${expr.$field}` };
43
17
  if (expr.$fn === "count") {
@@ -53,7 +27,8 @@ function buildMongoFilter(filter) {
53
27
  /**
54
28
  * Builds the common prefix stages: $match + $group._id from groupBy fields.
55
29
  * Shared by both full aggregate and count pipelines.
56
- */ function buildPrefix(query) {
30
+ */
31
+ function buildPrefix(query) {
57
32
  const controls = query.controls || {};
58
33
  const groupBy = controls.$groupBy ?? [];
59
34
  const pipeline = [{ $match: buildMongoFilter(query.filter) }];
@@ -66,6 +41,11 @@ function buildMongoFilter(filter) {
66
41
  controls
67
42
  };
68
43
  }
44
+ /**
45
+ * Builds a full MongoDB aggregation pipeline for GROUP BY queries.
46
+ *
47
+ * Pipeline: $match → $group → $project → $match(having) → $sort → $skip → $limit
48
+ */
69
49
  function buildAggregatePipeline(query) {
70
50
  const { pipeline, groupId, groupBy, controls } = buildPrefix(query);
71
51
  const groupStage = { _id: groupId };
@@ -85,6 +65,11 @@ function buildAggregatePipeline(query) {
85
65
  if (controls.$limit) pipeline.push({ $limit: controls.$limit });
86
66
  return pipeline;
87
67
  }
68
+ /**
69
+ * Builds a count-only pipeline: returns the number of distinct groups.
70
+ *
71
+ * Pipeline: $match → $group (just _id) → $project → $match(having) → $count
72
+ */
88
73
  function buildCountPipeline(query) {
89
74
  const { pipeline, groupId, groupBy, controls } = buildPrefix(query);
90
75
  pipeline.push({ $group: { _id: groupId } });
@@ -97,6 +82,5 @@ function buildCountPipeline(query) {
97
82
  pipeline.push({ $count: "count" });
98
83
  return pipeline;
99
84
  }
100
-
101
85
  //#endregion
102
- export { buildAggregatePipeline, buildCountPipeline };
86
+ export { buildAggregatePipeline, buildCountPipeline };