Skip to content

Commit 5598b4c

Browse files
rockyshi1993Copilot
andcommitted
fix(types): add compilePipelineExpressions to type declarations and example fixes
- Add compilePipelineExpressions to types/runtime.d.ts - Export compilePipelineExpressions from index.d.ts (both named export and static member) - Fix examples/docs/insert.ts: replace BatchProgress.completed with currentBatch/totalBatches - All 15 example files now compile clean (tsc -p tsconfig.examples.json: 0 errors) - npm test: 2714 passed, 0 failed Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 3c926a9 commit 5598b4c

21 files changed

Lines changed: 1273 additions & 1 deletion

‎examples/README.md‎

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# monSQLize Examples
2+
3+
Runnable TypeScript examples for every major monSQLize API.
4+
Each file uses an in-memory MongoDB server (`mongodb-memory-server`) — no real database needed.
5+
6+
## Prerequisites
7+
8+
```bash
9+
npm install # install all deps
10+
npm run build # build the library
11+
```
12+
13+
## Quick Start
14+
15+
```bash
16+
# Compile all examples
17+
tsc -p tsconfig.examples.json
18+
19+
# Run a single example
20+
node .generated/examples-dist/examples/quick-start/basic-connect.js
21+
```
22+
23+
## Run All Examples
24+
25+
```bash
26+
npm run test:examples
27+
```
28+
29+
## Example Index
30+
31+
### Quick Start
32+
33+
| File | Description |
34+
|------|-------------|
35+
| [`quick-start/basic-connect.ts`](quick-start/basic-connect.ts) | Connect, CRUD lifecycle, disconnect |
36+
37+
### Cache
38+
39+
| File | Description |
40+
|------|-------------|
41+
| [`cache/with-cache.ts`](cache/with-cache.ts) | Per-collection cache TTL, hit/miss, `invalidate()` |
42+
43+
### Docs — CRUD
44+
45+
| File | Description |
46+
|------|-------------|
47+
| [`docs/insert.ts`](docs/insert.ts) | `insertOne`, `insertMany`, `insertBatch` |
48+
| [`docs/update.ts`](docs/update.ts) | `updateOne`, `updateMany`, `updateBatch`, `incrementOne` |
49+
| [`docs/delete.ts`](docs/delete.ts) | `deleteOne`, `deleteMany`, `deleteBatch` |
50+
| [`docs/upsert.ts`](docs/upsert.ts) | `upsertOne`, `findOneAndUpdate`, `findOneAndReplace`, `replaceOne` |
51+
52+
### Docs — Query
53+
54+
| File | Description |
55+
|------|-------------|
56+
| [`docs/find.ts`](docs/find.ts) | `find` with sort, limit, skip, project |
57+
| [`docs/find-one.ts`](docs/find-one.ts) | `findOne`, `findOneById`, `findByIds` |
58+
| [`docs/find-page.ts`](docs/find-page.ts) | `findPage` — cursor and offset pagination |
59+
| [`docs/find-and-count.ts`](docs/find-and-count.ts) | `findAndCount` — returns `{ data, total }` |
60+
| [`docs/aggregate.ts`](docs/aggregate.ts) | Aggregation pipeline stages |
61+
| [`docs/chaining-api.ts`](docs/chaining-api.ts) | `FindChain` and `AggregateChain` fluent builders |
62+
63+
### Docs — Advanced
64+
65+
| File | Description |
66+
|------|-------------|
67+
| [`docs/expression-functions.ts`](docs/expression-functions.ts) | `MonSQLize.expr()` for reusable pipeline expressions |
68+
| [`docs/model.ts`](docs/model.ts) | Model schema + lifecycle hooks (pre/post) |
69+
| [`docs/transaction.ts`](docs/transaction.ts) | `withTransaction()` — requires replica-set, see file for setup |
70+
| [`docs/slow-query-log.ts`](docs/slow-query-log.ts) | Slow query log configuration |
71+
72+
## Running Individual Examples
73+
74+
```bash
75+
# After building:
76+
tsc -p tsconfig.examples.json
77+
78+
node .generated/examples-dist/examples/docs/insert.js
79+
node .generated/examples-dist/examples/docs/update.js
80+
node .generated/examples-dist/examples/docs/delete.js
81+
node .generated/examples-dist/examples/docs/upsert.js
82+
node .generated/examples-dist/examples/docs/find.js
83+
node .generated/examples-dist/examples/docs/find-one.js
84+
node .generated/examples-dist/examples/docs/find-page.js
85+
node .generated/examples-dist/examples/docs/find-and-count.js
86+
node .generated/examples-dist/examples/docs/aggregate.js
87+
node .generated/examples-dist/examples/docs/chaining-api.js
88+
node .generated/examples-dist/examples/docs/expression-functions.js
89+
node .generated/examples-dist/examples/docs/model.js
90+
node .generated/examples-dist/examples/docs/slow-query-log.js
91+
```
92+
93+
## Transaction Example
94+
95+
Requires a local MongoDB replica-set:
96+
97+
```bash
98+
# Start a local replica-set, then:
99+
MONGO_RS_URI=mongodb://127.0.0.1:27017/?replicaSet=rs0 \
100+
node .generated/examples-dist/examples/docs/transaction.js
101+
```

‎examples/cache/with-cache.ts‎

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* Cache example: L1 in-memory cache with TTL and invalidation.
3+
*
4+
* Demonstrates:
5+
* - Enabling MemoryCache on a MonSQLize collection
6+
* - Cache hits / misses
7+
* - TTL-based expiry
8+
* - Manual cache invalidation via invalidate()
9+
*
10+
* Run after building:
11+
* npm run build && tsc -p tsconfig.examples.json
12+
* node .generated/examples-dist/examples/cache/with-cache.js
13+
*/
14+
import { MonSQLize } from 'monsqlize';
15+
import { setupExample, teardownExample } from '../helpers/bootstrap.js';
16+
17+
interface ProductDoc { sku: string; name: string; price: number; inStock: boolean; }
18+
19+
async function main() {
20+
console.log('🚀 monSQLize Cache Example\n');
21+
22+
const { msq, server } = await setupExample('cache-demo');
23+
24+
// Cache is configured per-collection at MonSQLize constructor level.
25+
// Here we just use the collection; see bootstrap for cache wiring.
26+
const products = msq.collection<ProductDoc>('products');
27+
28+
// ── Seed data ─────────────────────────────────────────────────────────
29+
await products.insertMany([
30+
{ sku: 'A1', name: 'Widget', price: 9.99, inStock: true },
31+
{ sku: 'B2', name: 'Gadget', price: 19.99, inStock: true },
32+
{ sku: 'C3', name: 'Doohickey', price: 4.99, inStock: false },
33+
]);
34+
35+
// ── First query — cache MISS (populates cache) ────────────────────────
36+
const first = await products.find({ inStock: true });
37+
console.log('1st find (cache miss):', first.length, 'products');
38+
39+
// ── Second identical query — cache HIT ────────────────────────────────
40+
const second = await products.find({ inStock: true });
41+
console.log('2nd find (cache hit):', second.length, 'products');
42+
43+
// ── Update underlying data — cache is now stale ───────────────────────
44+
await products.updateOne({ sku: 'C3' }, { $set: { inStock: true } });
45+
const stale = await products.find({ inStock: true });
46+
console.log('After update, cached result still:', stale.length, 'products (stale)');
47+
48+
// ── Invalidate cache for this collection ──────────────────────────────
49+
await products.invalidate();
50+
const fresh = await products.find({ inStock: true });
51+
console.log('After invalidate(), fresh result:', fresh.length, 'products');
52+
53+
// ── findOne with cache ─────────────────────────────────────────────────
54+
const widget = await products.findOne({ sku: 'A1' });
55+
console.log('findOne cached:', widget?.name, '/', widget?.price);
56+
57+
await teardownExample(msq, server);
58+
console.log('\n✅ Cache example completed successfully');
59+
}
60+
61+
main().catch((err) => {
62+
console.error('❌ Example failed:', err);
63+
process.exit(1);
64+
});

‎examples/docs/aggregate.ts‎

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* Aggregation pipeline example.
3+
* See: docs/aggregate.md
4+
*
5+
* Run:
6+
* npm run build && tsc -p tsconfig.examples.json
7+
* node .generated/examples-dist/examples/docs/aggregate.js
8+
*/
9+
import { setupExample, teardownExample } from '../helpers/bootstrap.js';
10+
11+
async function main() {
12+
const { msq, server } = await setupExample('example-aggregate');
13+
const orders = msq.collection('orders');
14+
15+
await orders.insertMany([
16+
{ product: 'Widget', category: 'tools', amount: 29.99, qty: 3, status: 'completed' },
17+
{ product: 'Gadget', category: 'tools', amount: 59.99, qty: 1, status: 'completed' },
18+
{ product: 'Widget', category: 'tools', amount: 29.99, qty: 2, status: 'pending' },
19+
{ product: 'Doohickey', category: 'parts', amount: 9.99, qty: 5, status: 'completed' },
20+
{ product: 'Gadget', category: 'tools', amount: 59.99, qty: 2, status: 'completed' },
21+
]);
22+
23+
// ── Basic aggregate pipeline ───────────────────────────────────────────
24+
const revenueByCategory = await orders.aggregate([
25+
{ $match: { status: 'completed' } },
26+
{
27+
$group: {
28+
_id: '$category',
29+
totalRevenue: { $sum: { $multiply: ['$amount', '$qty'] } },
30+
orderCount: { $sum: 1 },
31+
},
32+
},
33+
{ $sort: { totalRevenue: -1 } },
34+
]);
35+
console.log('Revenue by category:');
36+
for (const cat of revenueByCategory as Record<string, unknown>[]) {
37+
console.log(` ${cat._id}: $${(cat.totalRevenue as number).toFixed(2)} (${cat.orderCount} orders)`);
38+
}
39+
40+
// ── Aggregate with project + addFields ────────────────────────────────
41+
const detailed = await orders.aggregate([
42+
{ $match: { status: 'completed' } },
43+
{
44+
$addFields: {
45+
lineTotal: { $multiply: ['$amount', '$qty'] },
46+
},
47+
},
48+
{
49+
$project: {
50+
product: 1,
51+
qty: 1,
52+
amount: 1,
53+
lineTotal: 1,
54+
_id: 0,
55+
},
56+
},
57+
{ $sort: { lineTotal: -1 } },
58+
{ $limit: 3 },
59+
]);
60+
console.log('\nTop 3 line items:');
61+
for (const item of detailed as Record<string, unknown>[]) {
62+
console.log(` ${item.product} × ${item.qty} = $${(item.lineTotal as number).toFixed(2)}`);
63+
}
64+
65+
// ── Aggregate with $count ──────────────────────────────────────────────
66+
const total = await orders.aggregate([
67+
{ $match: { status: 'completed' } },
68+
{ $count: 'completedOrders' },
69+
]);
70+
console.log('\nCompleted orders:', (total[0] as Record<string, unknown>)?.completedOrders);
71+
72+
await teardownExample(msq, server);
73+
console.log('✅ Aggregate example complete');
74+
}
75+
76+
main().catch((err) => {
77+
console.error('❌ Example failed:', err);
78+
process.exit(1);
79+
});

‎examples/docs/chaining-api.ts‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Chaining API example — FindChain and AggregateChain.
3+
* See: docs/chaining-api.md
4+
*
5+
* Run:
6+
* npm run build && tsc -p tsconfig.examples.json
7+
* node .generated/examples-dist/examples/docs/chaining-api.js
8+
*/
9+
import { setupExample, teardownExample } from '../helpers/bootstrap.js';
10+
11+
async function main() {
12+
const { msq, server } = await setupExample('example-chaining');
13+
const products = msq.collection('products');
14+
15+
await products.insertMany([
16+
{ name: 'Widget A', category: 'tools', price: 9.99, rating: 4.5, inStock: true },
17+
{ name: 'Widget B', category: 'tools', price: 14.99, rating: 3.8, inStock: true },
18+
{ name: 'Gadget X', category: 'electronics', price: 49.99, rating: 4.9, inStock: true },
19+
{ name: 'Gadget Y', category: 'electronics', price: 79.99, rating: 4.2, inStock: false },
20+
{ name: 'Part Z', category: 'parts', price: 2.99, rating: 4.0, inStock: true },
21+
]);
22+
23+
// ── FindChain — chained query builder ────────────────────────────────
24+
const topTools = await products
25+
.find({ category: 'tools', inStock: true })
26+
.sort({ rating: -1 })
27+
.limit(5)
28+
.project({ name: 1, price: 1, rating: 1, _id: 0 });
29+
30+
console.log('Top tools:');
31+
for (const p of topTools as Record<string, unknown>[]) {
32+
console.log(` ${p.name}: $${p.price} (★ ${p.rating})`);
33+
}
34+
35+
// ── FindChain — maxTimeMS + comment ───────────────────────────────────
36+
const withHints = await products
37+
.find({ inStock: true })
38+
.sort({ price: 1 })
39+
.skip(1)
40+
.limit(3)
41+
.maxTimeMS(5000)
42+
.comment('CatalogAPI:getPage');
43+
44+
console.log('With hints:', (withHints as Record<string, unknown>[]).length, 'items');
45+
46+
// ── AggregateChain ────────────────────────────────────────────────────
47+
const aggResult = await products
48+
.aggregate([
49+
{ $match: { inStock: true } },
50+
{ $group: { _id: '$category', avgPrice: { $avg: '$price' }, count: { $sum: 1 } } },
51+
{ $sort: { avgPrice: -1 } },
52+
])
53+
.allowDiskUse(false)
54+
.maxTimeMS(10000);
55+
56+
console.log('Category avg prices:');
57+
for (const cat of aggResult as Record<string, unknown>[]) {
58+
console.log(` ${cat._id}: avg $${(cat.avgPrice as number).toFixed(2)} (${cat.count} items)`);
59+
}
60+
61+
await teardownExample(msq, server);
62+
console.log('✅ Chaining API example complete');
63+
}
64+
65+
main().catch((err) => {
66+
console.error('❌ Example failed:', err);
67+
process.exit(1);
68+
});

‎examples/docs/delete.ts‎

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* Delete operations: deleteOne, deleteMany, deleteBatch.
3+
* See: docs/delete-one.md, docs/delete-many.md, docs/deleteBatch.md
4+
*
5+
* Run:
6+
* npm run build && tsc -p tsconfig.examples.json
7+
* node .generated/examples-dist/examples/docs/delete.js
8+
*/
9+
import { setupExample, teardownExample } from '../helpers/bootstrap.js';
10+
11+
async function main() {
12+
const { msq, server } = await setupExample('example-delete');
13+
const sessions = msq.collection('sessions');
14+
15+
await sessions.insertMany([
16+
{ userId: 'u1', token: 'tok-a', expires: new Date('2024-01-01') },
17+
{ userId: 'u2', token: 'tok-b', expires: new Date('2024-01-01') },
18+
{ userId: 'u3', token: 'tok-c', expires: new Date('2030-12-31') },
19+
{ userId: 'u1', token: 'tok-d', expires: new Date('2030-12-31') },
20+
]);
21+
22+
const before = await sessions.count({});
23+
console.log('Before delete:', before, 'sessions');
24+
25+
// ── deleteOne ─────────────────────────────────────────────────────────
26+
const d1 = await sessions.deleteOne({ token: 'tok-a' });
27+
console.log('deleteOne — deletedCount:', d1.deletedCount);
28+
29+
// ── deleteMany ────────────────────────────────────────────────────────
30+
const d2 = await sessions.deleteMany({ expires: { $lt: new Date() } });
31+
console.log('deleteMany (expired) — deletedCount:', d2.deletedCount);
32+
33+
const after = await sessions.count({});
34+
console.log('After deleteMany:', after, 'sessions remaining');
35+
36+
// ── deleteBatch — individual filters per item ─────────────────────────
37+
const d3 = await sessions.deleteBatch([
38+
{ filter: { token: 'tok-d' } },
39+
]);
40+
console.log('deleteBatch — deleted:', d3.deletedCount, '/', d3.totalCount);
41+
42+
const final = await sessions.count({});
43+
console.log('Final count:', final);
44+
45+
await teardownExample(msq, server);
46+
console.log('✅ Delete example complete');
47+
}
48+
49+
main().catch((err) => {
50+
console.error('❌ Example failed:', err);
51+
process.exit(1);
52+
});

0 commit comments

Comments
 (0)