@owlmeans/mongo-resource 0.1.15 → 0.1.16
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 +54 -10
- package/agent-meta/manifest.json +4 -11
- package/agent-meta/skills/mongo-resource/SKILL.md +150 -17
- package/build/consts.d.ts +16 -0
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +16 -0
- package/build/consts.js.map +1 -1
- package/build/declarations.d.ts +11 -0
- package/build/declarations.d.ts.map +1 -0
- package/build/declarations.js +29 -0
- package/build/declarations.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -0
- package/build/index.js.map +1 -1
- package/build/resource.d.ts.map +1 -1
- package/build/resource.js +58 -23
- package/build/resource.js.map +1 -1
- package/build/types.d.ts +53 -2
- package/build/types.d.ts.map +1 -1
- package/build/utils/index.d.ts +2 -0
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js +2 -0
- package/build/utils/index.js.map +1 -1
- package/build/utils/life-cycle.d.ts +25 -1
- package/build/utils/life-cycle.d.ts.map +1 -1
- package/build/utils/life-cycle.js +89 -11
- package/build/utils/life-cycle.js.map +1 -1
- package/build/utils/migrations.d.ts +24 -0
- package/build/utils/migrations.d.ts.map +1 -0
- package/build/utils/migrations.js +129 -0
- package/build/utils/migrations.js.map +1 -0
- package/build/utils/refs.d.ts +74 -0
- package/build/utils/refs.d.ts.map +1 -0
- package/build/utils/refs.js +197 -0
- package/build/utils/refs.js.map +1 -0
- package/build/utils/schema.d.ts +8 -0
- package/build/utils/schema.d.ts.map +1 -1
- package/build/utils/schema.js +25 -0
- package/build/utils/schema.js.map +1 -1
- package/package.json +5 -5
- package/src/consts.ts +20 -0
- package/src/declarations.ts +42 -0
- package/src/index.ts +4 -1
- package/src/resource.ts +76 -28
- package/src/types.ts +58 -2
- package/src/utils/index.ts +2 -0
- package/src/utils/life-cycle.ts +117 -15
- package/src/utils/migrations.ts +171 -0
- package/src/utils/refs.ts +240 -0
- package/src/utils/schema.ts +32 -0
- package/tests/refs.spec.ts +95 -0
- package/agent-meta/instructions/mongo-resource.instructions.md +0 -30
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import { MisshapedRecord } from '@owlmeans/resource'
|
|
3
|
+
import { ObjectId } from 'mongodb'
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
demarshalReference, demarshalRefs, identityCriteria, isObjectIdHex, marshalCriteria,
|
|
7
|
+
marshalReference, refMigrationName
|
|
8
|
+
} from '../src/utils/refs.js'
|
|
9
|
+
import type { MongoReference } from '../src/types.js'
|
|
10
|
+
|
|
11
|
+
const HEX = '6712abcdef0123456789abcd'
|
|
12
|
+
const OTHER = '6712abcdef0123456789abce'
|
|
13
|
+
|
|
14
|
+
const refs = (...fields: string[]): Map<string, MongoReference> =>
|
|
15
|
+
new Map(fields.map(field => [field, { field }]))
|
|
16
|
+
|
|
17
|
+
describe('reference marshalling', () => {
|
|
18
|
+
test('converts 24-hex strings and arrays, passes null and ObjectId through', () => {
|
|
19
|
+
expect(marshalReference('userId', HEX)).toEqual(new ObjectId(HEX))
|
|
20
|
+
const present = new ObjectId(HEX)
|
|
21
|
+
expect(marshalReference('userId', present)).toBe(present)
|
|
22
|
+
expect(marshalReference('userId', null)).toBeNull()
|
|
23
|
+
expect(marshalReference('userId', undefined)).toBeUndefined()
|
|
24
|
+
expect(marshalReference('userId', [HEX, OTHER])).toEqual([new ObjectId(HEX), new ObjectId(OTHER)])
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('refuses a value that is not a mongo id', () => {
|
|
28
|
+
expect(() => marshalReference('userId', 'not-an-id')).toThrow(MisshapedRecord)
|
|
29
|
+
/** 12 characters — the shape `ObjectId.isValid` wrongly accepts. */
|
|
30
|
+
expect(() => marshalReference('userId', 'abcdefghijkl')).toThrow(MisshapedRecord)
|
|
31
|
+
expect(() => marshalReference('userId', 42)).toThrow(MisshapedRecord)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('demarshals ObjectIds back to strings, tolerating unconverted values', () => {
|
|
35
|
+
expect(demarshalReference(new ObjectId(HEX))).toBe(HEX)
|
|
36
|
+
expect(demarshalReference([new ObjectId(HEX), 'legacy'])).toEqual([HEX, 'legacy'])
|
|
37
|
+
expect(demarshalReference('legacy')).toBe('legacy')
|
|
38
|
+
const record = { userId: new ObjectId(HEX), other: 'x' }
|
|
39
|
+
expect(demarshalRefs(record, refs('userId')).userId).toBe(HEX as never)
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('isObjectIdHex accepts exactly the 24-hex shape', () => {
|
|
43
|
+
expect(isObjectIdHex(HEX)).toBe(true)
|
|
44
|
+
expect(isObjectIdHex('abcdefghijkl')).toBe(false)
|
|
45
|
+
expect(isObjectIdHex(HEX + 'ff')).toBe(false)
|
|
46
|
+
expect(isObjectIdHex(new ObjectId(HEX))).toBe(false)
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('criteria marshalling', () => {
|
|
51
|
+
test('converts ref fields and maps id onto _id', () => {
|
|
52
|
+
const converted = marshalCriteria({ userId: HEX, id: OTHER, title: HEX } as never, refs('userId'))!
|
|
53
|
+
expect(converted.userId).toEqual(new ObjectId(HEX) as never)
|
|
54
|
+
expect(converted._id).toEqual(new ObjectId(OTHER) as never)
|
|
55
|
+
expect('id' in converted).toBe(false)
|
|
56
|
+
/** Not declared — even a 24-hex value stays a string. */
|
|
57
|
+
expect(converted.title).toBe(HEX)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('converts inside operators and logical branches, skips opaque operators', () => {
|
|
61
|
+
const converted = marshalCriteria({
|
|
62
|
+
userId: { $in: [HEX, 'garbage'] },
|
|
63
|
+
$or: [{ userId: HEX }, { userId: { $ne: OTHER } }],
|
|
64
|
+
slug: { $regex: HEX }
|
|
65
|
+
} as never, refs('userId'))!
|
|
66
|
+
expect((converted.userId as never as { $in: unknown[] }).$in).toEqual([new ObjectId(HEX), 'garbage'])
|
|
67
|
+
const or = converted.$or as never as [{ userId: unknown }, { userId: { $ne: unknown } }]
|
|
68
|
+
expect(or[0].userId).toEqual(new ObjectId(HEX))
|
|
69
|
+
expect(or[1].userId.$ne).toEqual(new ObjectId(OTHER))
|
|
70
|
+
expect((converted.slug as never as { $regex: string }).$regex).toBe(HEX)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
test('passes values that are not mongo ids through untouched', () => {
|
|
74
|
+
const converted = marshalCriteria({ userId: 'one-time-token:6712' } as never, refs('userId'))!
|
|
75
|
+
expect(converted.userId).toBe('one-time-token:6712')
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
describe('identity criteria', () => {
|
|
80
|
+
test('addresses _id strictly, id and refs tolerantly', () => {
|
|
81
|
+
expect(identityCriteria('_id', HEX, refs())).toEqual({ _id: new ObjectId(HEX) })
|
|
82
|
+
expect(identityCriteria('id', HEX, refs())).toEqual({ _id: new ObjectId(HEX) })
|
|
83
|
+
expect(identityCriteria('id', 'garbage', refs())).toEqual({ _id: 'garbage' })
|
|
84
|
+
expect(identityCriteria('userId', HEX, refs('userId'))).toEqual({ userId: new ObjectId(HEX) })
|
|
85
|
+
expect(identityCriteria('userId', 'ext:key', refs('userId'))).toEqual({ userId: 'ext:key' })
|
|
86
|
+
expect(identityCriteria('slug', HEX, refs())).toEqual({ slug: HEX })
|
|
87
|
+
expect(() => identityCriteria('_id', 'garbage', refs())).toThrow()
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
describe('system migration naming', () => {
|
|
92
|
+
test('carries the field and the body version', () => {
|
|
93
|
+
expect(refMigrationName('userId')).toBe('$ref:userId@1')
|
|
94
|
+
})
|
|
95
|
+
})
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "How to use @owlmeans/mongo-resource — MongoDB-backed Resource implementation. Builds a typed CRUD resource on top of @owlmeans/mongo."
|
|
3
|
-
applyTo: "**/*.ts, **/*.tsx"
|
|
4
|
-
---
|
|
5
|
-
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
6
|
-
|
|
7
|
-
# @owlmeans/mongo-resource
|
|
8
|
-
|
|
9
|
-
**Layer:** Infra
|
|
10
|
-
**Install:** `"@owlmeans/mongo-resource": "^0.1.15"` in `dependencies`
|
|
11
|
-
|
|
12
|
-
## Key Exports
|
|
13
|
-
|
|
14
|
-
| Export | Description |
|
|
15
|
-
|--------|-------------|
|
|
16
|
-
| `makeMongoResource<T>(options)` | MongoDB-backed Resource factory |
|
|
17
|
-
| `MongoResource<T>` types | Resource interface |
|
|
18
|
-
| Constants | Default collection prefix |
|
|
19
|
-
| Helpers | Index creation, query helpers |
|
|
20
|
-
|
|
21
|
-
## Usage
|
|
22
|
-
|
|
23
|
-
```typescript
|
|
24
|
-
import { makeMongoResource } from '@owlmeans/mongo-resource'
|
|
25
|
-
context.registerResource(makeMongoResource<Project>({ alias: 'projects', collection: 'projects' }))
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
## Depends On
|
|
29
|
-
|
|
30
|
-
- `@owlmeans/mongo`, `@owlmeans/resource`, `@owlmeans/server-context`
|