@classytic/repo-core 0.1.0
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/CHANGELOG.md +67 -0
- package/LICENSE +21 -0
- package/README.md +154 -0
- package/dist/cache/index.d.mts +4 -0
- package/dist/cache/index.mjs +3 -0
- package/dist/cache/memory-adapter.d.mts +7 -0
- package/dist/cache/memory-adapter.mjs +37 -0
- package/dist/cache/stable-stringify.d.mts +15 -0
- package/dist/cache/stable-stringify.mjs +19 -0
- package/dist/cache/types.d.mts +59 -0
- package/dist/context/index.d.mts +2 -0
- package/dist/context/index.mjs +0 -0
- package/dist/context/types.d.mts +24 -0
- package/dist/errors/create-error.d.mts +19 -0
- package/dist/errors/create-error.mjs +23 -0
- package/dist/errors/duplicate-key.d.mts +38 -0
- package/dist/errors/duplicate-key.mjs +57 -0
- package/dist/errors/index.d.mts +4 -0
- package/dist/errors/index.mjs +3 -0
- package/dist/errors/types.d.mts +37 -0
- package/dist/filter/builders.d.mts +60 -0
- package/dist/filter/builders.mjs +172 -0
- package/dist/filter/guard.d.mts +13 -0
- package/dist/filter/guard.mjs +34 -0
- package/dist/filter/index.d.mts +7 -0
- package/dist/filter/index.mjs +6 -0
- package/dist/filter/match.d.mts +12 -0
- package/dist/filter/match.mjs +91 -0
- package/dist/filter/scope.d.mts +31 -0
- package/dist/filter/scope.mjs +54 -0
- package/dist/filter/types.d.mts +143 -0
- package/dist/filter/walk.d.mts +24 -0
- package/dist/filter/walk.mjs +77 -0
- package/dist/hooks/engine.d.mts +48 -0
- package/dist/hooks/engine.mjs +101 -0
- package/dist/hooks/events.d.mts +95 -0
- package/dist/hooks/events.mjs +93 -0
- package/dist/hooks/index.d.mts +5 -0
- package/dist/hooks/index.mjs +4 -0
- package/dist/hooks/priority.d.mts +23 -0
- package/dist/hooks/priority.mjs +21 -0
- package/dist/hooks/types.d.mts +37 -0
- package/dist/lookup/index.d.mts +2 -0
- package/dist/lookup/index.mjs +0 -0
- package/dist/lookup/types.d.mts +170 -0
- package/dist/operations/index.d.mts +3 -0
- package/dist/operations/index.mjs +2 -0
- package/dist/operations/registry.d.mts +41 -0
- package/dist/operations/registry.mjs +140 -0
- package/dist/operations/types.d.mts +49 -0
- package/dist/pagination/cursor.d.mts +44 -0
- package/dist/pagination/cursor.mjs +150 -0
- package/dist/pagination/index.d.mts +5 -0
- package/dist/pagination/index.mjs +4 -0
- package/dist/pagination/keyset.d.mts +25 -0
- package/dist/pagination/keyset.mjs +61 -0
- package/dist/pagination/offset.d.mts +26 -0
- package/dist/pagination/offset.mjs +47 -0
- package/dist/pagination/types.d.mts +136 -0
- package/dist/query-parser/coerce.d.mts +16 -0
- package/dist/query-parser/coerce.mjs +73 -0
- package/dist/query-parser/index.d.mts +4 -0
- package/dist/query-parser/index.mjs +3 -0
- package/dist/query-parser/parse-url.d.mts +7 -0
- package/dist/query-parser/parse-url.mjs +224 -0
- package/dist/query-parser/types.d.mts +104 -0
- package/dist/repository/base.d.mts +90 -0
- package/dist/repository/base.mjs +111 -0
- package/dist/repository/index.d.mts +5 -0
- package/dist/repository/index.mjs +3 -0
- package/dist/repository/plugin-types.d.mts +27 -0
- package/dist/repository/plugin-types.mjs +45 -0
- package/dist/repository/types.d.mts +470 -0
- package/dist/schema/field-rules.d.mts +62 -0
- package/dist/schema/field-rules.mjs +110 -0
- package/dist/schema/index.d.mts +3 -0
- package/dist/schema/index.mjs +2 -0
- package/dist/schema/types.d.mts +138 -0
- package/dist/testing/conformance.d.mts +6 -0
- package/dist/testing/conformance.mjs +481 -0
- package/dist/testing/index.d.mts +3 -0
- package/dist/testing/index.mjs +2 -0
- package/dist/testing/types.d.mts +113 -0
- package/package.json +130 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { MinimalRepo, StandardRepo } from "../repository/types.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/testing/types.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The conformance scenarios operate on a minimal doc shape common to
|
|
6
|
+
* every backend:
|
|
7
|
+
*
|
|
8
|
+
* - `name`, `email`, `category`, `active`, `count`, `notes` — plain
|
|
9
|
+
* scalar fields every driver supports.
|
|
10
|
+
* - `createdAt` — ISO string. Avoids Date/epoch coercion divergence.
|
|
11
|
+
* - `_id` / `id` — the harness decides which one its backend uses;
|
|
12
|
+
* scenarios read it via `harness.idField`.
|
|
13
|
+
*
|
|
14
|
+
* The intent is to keep the schema lowest-common-denominator, not to
|
|
15
|
+
* exercise backend-specific features (JSON mode, BSON subdocs, vector
|
|
16
|
+
* fields). Those stay per-kit.
|
|
17
|
+
*/
|
|
18
|
+
interface ConformanceDoc {
|
|
19
|
+
id?: string;
|
|
20
|
+
_id?: string;
|
|
21
|
+
name: string;
|
|
22
|
+
email: string;
|
|
23
|
+
category: string | null;
|
|
24
|
+
count: number;
|
|
25
|
+
active: boolean;
|
|
26
|
+
notes: string | null;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Per-backend feature flags. Scenarios that exercise a non-universal
|
|
31
|
+
* capability (transactions in D1, upsert in narrow stores) check the
|
|
32
|
+
* flag and `it.skip` on the off branch — so the suite runs on every
|
|
33
|
+
* environment without "optional test failed" noise.
|
|
34
|
+
*/
|
|
35
|
+
interface ConformanceFeatures {
|
|
36
|
+
/** `withTransaction(fn)` — D1 throws, standalone Mongo throws 263. */
|
|
37
|
+
transactions: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* True if calling `withTransaction` inside another `withTransaction`
|
|
40
|
+
* callback is expected to work. Mongo's driver supports it via the
|
|
41
|
+
* same session; SQL drivers typically reject it. Either behavior is
|
|
42
|
+
* valid — the scenario asserts whichever the harness declares.
|
|
43
|
+
*/
|
|
44
|
+
nestedTransactions: boolean;
|
|
45
|
+
/** `findOneAndUpdate` with upsert: true. */
|
|
46
|
+
upsert: boolean;
|
|
47
|
+
/** `isDuplicateKeyError(err)` classifier. */
|
|
48
|
+
duplicateKeyError: boolean;
|
|
49
|
+
/** `distinct(field)`. */
|
|
50
|
+
distinct: boolean;
|
|
51
|
+
/** Portable `aggregate({ measures, groupBy, having })`. */
|
|
52
|
+
aggregate: boolean;
|
|
53
|
+
/** `getOrCreate(filter, data)`. */
|
|
54
|
+
getOrCreate: boolean;
|
|
55
|
+
/** `count(filter)` and `exists(filter)`. */
|
|
56
|
+
countAndExists: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* One-shot context produced by `harness.setup()`. Scenarios receive a
|
|
60
|
+
* fresh context per test — the harness is responsible for isolation
|
|
61
|
+
* (new collection name on mongo, fresh `:memory:` db on sqlite).
|
|
62
|
+
*/
|
|
63
|
+
interface ConformanceContext<TDoc extends ConformanceDoc = ConformanceDoc> {
|
|
64
|
+
/** Repository under test. */
|
|
65
|
+
repo: StandardRepo<TDoc> & MinimalRepo<TDoc>;
|
|
66
|
+
/**
|
|
67
|
+
* Optional secondary repository pointing at a DIFFERENT collection /
|
|
68
|
+
* table — scenarios that exercise cross-repo atomicity use it. May
|
|
69
|
+
* be omitted; scenarios that need it will skip if missing.
|
|
70
|
+
*/
|
|
71
|
+
secondaryRepo?: StandardRepo<TDoc> & MinimalRepo<TDoc>;
|
|
72
|
+
/** Release resources (close db, drop collection). Must be idempotent. */
|
|
73
|
+
cleanup(): Promise<void>;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Harness plugged into `runStandardRepoConformance`.
|
|
77
|
+
*
|
|
78
|
+
* The harness owns:
|
|
79
|
+
* - Backend bootstrap (mongo connection, sqlite db + migrations).
|
|
80
|
+
* - Doc factory — returns a partial doc with default values filled in.
|
|
81
|
+
* Scenarios call `makeDoc({ name: 'override' })` to produce inserts.
|
|
82
|
+
* - Feature flags — declares what the backend supports.
|
|
83
|
+
* - idField — `'id'` for sqlitekit, `'_id'` for mongokit. Scenarios
|
|
84
|
+
* read this to project the primary key off returned docs.
|
|
85
|
+
*/
|
|
86
|
+
interface ConformanceHarness<TDoc extends ConformanceDoc = ConformanceDoc> {
|
|
87
|
+
/** Human-readable kit name, used as the top-level describe() label. */
|
|
88
|
+
name: string;
|
|
89
|
+
/**
|
|
90
|
+
* Name of the primary-key field on docs the repo returns. `'id'` for
|
|
91
|
+
* sqlitekit, `'_id'` for mongokit, could be `'uuid'` or anything else
|
|
92
|
+
* for future kits. Scenarios read ids via `doc[idField]`.
|
|
93
|
+
*/
|
|
94
|
+
idField: string;
|
|
95
|
+
/** Feature support flags — skipped scenarios show as `skipped` in vitest output. */
|
|
96
|
+
features: ConformanceFeatures;
|
|
97
|
+
/** Create a fresh, isolated repo + cleanup closure. Called per test. */
|
|
98
|
+
setup(): Promise<ConformanceContext<TDoc>>;
|
|
99
|
+
/**
|
|
100
|
+
* Build a partial doc with fixture-safe defaults. Passed-in overrides
|
|
101
|
+
* merge on top. Do NOT include `id`/`_id` unless the caller overrides
|
|
102
|
+
* (scenarios usually let the backend assign or set one explicitly).
|
|
103
|
+
*
|
|
104
|
+
* Overrides are typed against `ConformanceDoc` (not `TDoc`) because
|
|
105
|
+
* the shared scenarios only know the common doc shape. Kits that use
|
|
106
|
+
* a wider `TDoc` with extra required fields fill those in inside
|
|
107
|
+
* their harness's `makeDoc` implementation — the scenarios never
|
|
108
|
+
* reference them.
|
|
109
|
+
*/
|
|
110
|
+
makeDoc(overrides?: Partial<ConformanceDoc>): Partial<TDoc>;
|
|
111
|
+
}
|
|
112
|
+
//#endregion
|
|
113
|
+
export { ConformanceContext, ConformanceDoc, ConformanceFeatures, ConformanceHarness };
|
package/package.json
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@classytic/repo-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Driver-agnostic repository primitives: hooks, Filter IR, operations, pagination, cache contract. Foundation for mongokit, sqlitekit, pgkit, and prismakit. Lean by design — no plugins ship here; each kit owns its own.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE",
|
|
11
|
+
"CHANGELOG.md"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=22"
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
"./hooks": {
|
|
18
|
+
"types": "./dist/hooks/index.d.mts",
|
|
19
|
+
"default": "./dist/hooks/index.mjs"
|
|
20
|
+
},
|
|
21
|
+
"./operations": {
|
|
22
|
+
"types": "./dist/operations/index.d.mts",
|
|
23
|
+
"default": "./dist/operations/index.mjs"
|
|
24
|
+
},
|
|
25
|
+
"./errors": {
|
|
26
|
+
"types": "./dist/errors/index.d.mts",
|
|
27
|
+
"default": "./dist/errors/index.mjs"
|
|
28
|
+
},
|
|
29
|
+
"./pagination": {
|
|
30
|
+
"types": "./dist/pagination/index.d.mts",
|
|
31
|
+
"default": "./dist/pagination/index.mjs"
|
|
32
|
+
},
|
|
33
|
+
"./repository": {
|
|
34
|
+
"types": "./dist/repository/index.d.mts",
|
|
35
|
+
"default": "./dist/repository/index.mjs"
|
|
36
|
+
},
|
|
37
|
+
"./filter": {
|
|
38
|
+
"types": "./dist/filter/index.d.mts",
|
|
39
|
+
"default": "./dist/filter/index.mjs"
|
|
40
|
+
},
|
|
41
|
+
"./query-parser": {
|
|
42
|
+
"types": "./dist/query-parser/index.d.mts",
|
|
43
|
+
"default": "./dist/query-parser/index.mjs"
|
|
44
|
+
},
|
|
45
|
+
"./context": {
|
|
46
|
+
"types": "./dist/context/index.d.mts",
|
|
47
|
+
"default": "./dist/context/index.mjs"
|
|
48
|
+
},
|
|
49
|
+
"./cache": {
|
|
50
|
+
"types": "./dist/cache/index.d.mts",
|
|
51
|
+
"default": "./dist/cache/index.mjs"
|
|
52
|
+
},
|
|
53
|
+
"./schema": {
|
|
54
|
+
"types": "./dist/schema/index.d.mts",
|
|
55
|
+
"default": "./dist/schema/index.mjs"
|
|
56
|
+
},
|
|
57
|
+
"./testing": {
|
|
58
|
+
"types": "./dist/testing/index.d.mts",
|
|
59
|
+
"default": "./dist/testing/index.mjs"
|
|
60
|
+
},
|
|
61
|
+
"./lookup": {
|
|
62
|
+
"types": "./dist/lookup/index.d.mts",
|
|
63
|
+
"default": "./dist/lookup/index.mjs"
|
|
64
|
+
},
|
|
65
|
+
"./package.json": "./package.json"
|
|
66
|
+
},
|
|
67
|
+
"keywords": [
|
|
68
|
+
"repository",
|
|
69
|
+
"repository-pattern",
|
|
70
|
+
"data-access",
|
|
71
|
+
"hooks",
|
|
72
|
+
"filter-ir",
|
|
73
|
+
"pagination",
|
|
74
|
+
"cursor-pagination",
|
|
75
|
+
"keyset-pagination",
|
|
76
|
+
"plugin-based",
|
|
77
|
+
"driver-agnostic",
|
|
78
|
+
"typescript",
|
|
79
|
+
"esm"
|
|
80
|
+
],
|
|
81
|
+
"author": "Classytic <classytic.dev@gmail.com> (https://github.com/classytic)",
|
|
82
|
+
"license": "MIT",
|
|
83
|
+
"repository": {
|
|
84
|
+
"type": "git",
|
|
85
|
+
"url": "git+https://github.com/classytic/repo-core.git"
|
|
86
|
+
},
|
|
87
|
+
"bugs": {
|
|
88
|
+
"url": "https://github.com/classytic/repo-core/issues"
|
|
89
|
+
},
|
|
90
|
+
"homepage": "https://github.com/classytic/repo-core#readme",
|
|
91
|
+
"scripts": {
|
|
92
|
+
"build": "tsdown",
|
|
93
|
+
"dev": "tsdown --watch",
|
|
94
|
+
"test": "vitest run --project unit --project integration",
|
|
95
|
+
"test:unit": "vitest run --project unit",
|
|
96
|
+
"test:integration": "vitest run --project integration",
|
|
97
|
+
"test:e2e": "vitest run --project e2e",
|
|
98
|
+
"test:all": "vitest run",
|
|
99
|
+
"test:watch": "vitest --project unit --project integration",
|
|
100
|
+
"test:coverage": "vitest run --coverage",
|
|
101
|
+
"typecheck": "tsc --noEmit && tsc -p tsconfig.test.json",
|
|
102
|
+
"lint": "biome check src tests",
|
|
103
|
+
"lint:fix": "biome check src tests --write",
|
|
104
|
+
"format": "biome format src tests --write",
|
|
105
|
+
"check": "biome ci src tests --diagnostic-level=error",
|
|
106
|
+
"knip": "knip",
|
|
107
|
+
"prepublishOnly": "npm run check && npm run build && npm run typecheck && npm test",
|
|
108
|
+
"publish:dry": "npm publish --dry-run --access public",
|
|
109
|
+
"publish:npm": "npm publish --access public"
|
|
110
|
+
},
|
|
111
|
+
"devDependencies": {
|
|
112
|
+
"@arethetypeswrong/cli": "^0.18.2",
|
|
113
|
+
"@biomejs/biome": "^2.4.12",
|
|
114
|
+
"@types/node": "^22.0.0",
|
|
115
|
+
"@vitest/coverage-v8": "^4.1.4",
|
|
116
|
+
"knip": "^6.3.0",
|
|
117
|
+
"publint": "^0.3.18",
|
|
118
|
+
"tsdown": "^0.21.8",
|
|
119
|
+
"typescript": "^6.0.3",
|
|
120
|
+
"vitest": "^4.1.4"
|
|
121
|
+
},
|
|
122
|
+
"peerDependencies": {
|
|
123
|
+
"vitest": "^3.0.0 || ^4.0.0"
|
|
124
|
+
},
|
|
125
|
+
"peerDependenciesMeta": {
|
|
126
|
+
"vitest": {
|
|
127
|
+
"optional": true
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|