@atscript/db-mongo 0.1.39 → 0.1.41
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 +11 -11
- package/dist/agg.cjs +26 -65
- package/dist/{agg.d.ts → agg.d.cts} +5 -12
- package/dist/agg.d.mts +18 -0
- package/dist/agg.mjs +19 -35
- package/dist/index.cjs +374 -313
- package/dist/index.d.cts +344 -0
- package/dist/index.d.mts +344 -0
- package/dist/index.mjs +364 -301
- package/dist/mongo-filter-B5ZINZPF.cjs +40 -0
- package/dist/{mongo-filter-CL69Yhcm.mjs → mongo-filter-CcQO-sEh.mjs} +9 -4
- package/dist/plugin.cjs +37 -47
- package/dist/plugin.d.cts +6 -0
- package/dist/plugin.d.mts +6 -0
- package/dist/plugin.mjs +22 -11
- package/package.json +25 -44
- package/scripts/setup-skills.js +53 -43
- package/skills/atscript-db-mongo/SKILL.md +11 -11
- package/skills/atscript-db-mongo/collections.md +29 -28
- package/skills/atscript-db-mongo/core.md +6 -5
- package/skills/atscript-db-mongo/patches.md +17 -16
- package/LICENSE +0 -21
- package/dist/agg-CUX5Jb_A.mjs +0 -75
- package/dist/agg-FBVtOv9k.cjs +0 -77
- package/dist/index.d.ts +0 -336
- package/dist/mongo-filter-C8w5by9H.cjs +0 -65
- package/dist/plugin.d.ts +0 -5
package/README.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="https://atscript.
|
|
2
|
+
<img src="https://db.atscript.dev/logo.svg" alt="Atscript" width="120" />
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
5
|
<h1 align="center">@atscript/db-mongo</h1>
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="https://atscript.
|
|
12
|
+
<a href="https://db.atscript.dev">Documentation</a> · <a href="https://db.atscript.dev/adapters/mongodb">MongoDB Adapter</a>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
---
|
|
@@ -27,15 +27,15 @@ pnpm add @atscript/db-mongo mongodb
|
|
|
27
27
|
## Quick Start
|
|
28
28
|
|
|
29
29
|
```typescript
|
|
30
|
-
import { DbSpace } from
|
|
31
|
-
import { MongoAdapter } from
|
|
32
|
-
import { MongoClient } from
|
|
30
|
+
import { DbSpace } from "@atscript/db";
|
|
31
|
+
import { MongoAdapter } from "@atscript/db-mongo";
|
|
32
|
+
import { MongoClient } from "mongodb";
|
|
33
33
|
|
|
34
|
-
const client = new MongoClient(
|
|
35
|
-
const db = new DbSpace(() => new MongoAdapter(client.db(), client))
|
|
36
|
-
const todos = db.getTable(TodoType)
|
|
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
37
|
|
|
38
|
-
await todos.insertOne({ title:
|
|
38
|
+
await todos.insertOne({ title: "Hello", done: false });
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
## Features
|
|
@@ -52,8 +52,8 @@ await todos.insertOne({ title: 'Hello', done: false })
|
|
|
52
52
|
|
|
53
53
|
## Documentation
|
|
54
54
|
|
|
55
|
-
- [MongoDB Adapter Guide](https://atscript.
|
|
56
|
-
- [Full Documentation](https://atscript.
|
|
55
|
+
- [MongoDB Adapter Guide](https://db.atscript.dev/adapters/mongodb)
|
|
56
|
+
- [Full Documentation](https://db.atscript.dev)
|
|
57
57
|
|
|
58
58
|
## License
|
|
59
59
|
|
package/dist/agg.cjs
CHANGED
|
@@ -1,59 +1,9 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
*/
|
|
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
|
-
*/
|
|
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,
|
|
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
|
|
2
|
-
import { Document } from
|
|
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
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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
|
-
*/
|
|
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
|
-
*/
|
|
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 };
|