sonamu 0.10.7 → 0.10.9

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.
Files changed (79) hide show
  1. package/dist/api/decorators.d.ts.map +1 -1
  2. package/dist/api/decorators.js +5 -12
  3. package/dist/bin/cli.js +10 -253
  4. package/dist/database/base-model.d.ts +1 -0
  5. package/dist/database/base-model.d.ts.map +1 -1
  6. package/dist/database/base-model.js +14 -8
  7. package/dist/database/db.d.ts +2 -1
  8. package/dist/database/db.d.ts.map +1 -1
  9. package/dist/database/db.js +13 -3
  10. package/dist/database/puri-wrapper.d.ts.map +1 -1
  11. package/dist/database/puri-wrapper.js +4 -11
  12. package/dist/database/transaction-context.d.ts +8 -3
  13. package/dist/database/transaction-context.d.ts.map +1 -1
  14. package/dist/database/transaction-context.js +12 -7
  15. package/dist/migration/code-generation.js +2 -2
  16. package/dist/naite/naite-reporter.d.ts +8 -3
  17. package/dist/naite/naite-reporter.d.ts.map +1 -1
  18. package/dist/naite/naite-reporter.js +9 -4
  19. package/dist/ui-web/assets/{index-D0MHYbxl.js → index-CJf8uJYf.js} +47 -41
  20. package/dist/ui-web/assets/index-GMMIVGja.css +1 -0
  21. package/dist/ui-web/index.html +2 -2
  22. package/package.json +3 -3
  23. package/src/api/decorators.ts +11 -22
  24. package/src/bin/cli.ts +12 -375
  25. package/src/database/__tests__/transaction-scope.test.ts +227 -0
  26. package/src/database/base-model.ts +31 -6
  27. package/src/database/db.ts +17 -2
  28. package/src/database/puri-wrapper.ts +5 -22
  29. package/src/database/transaction-context.ts +14 -6
  30. package/src/migration/code-generation.ts +1 -1
  31. package/src/naite/naite-reporter.ts +8 -3
  32. package/dist/ui-web/assets/index-Dx_JX4aQ.css +0 -1
  33. package/src/skills/AGENTS.md +0 -108
  34. package/src/skills/sonamu/SKILL.md +0 -75
  35. package/src/skills/sonamu-ai-agents/SKILL.md +0 -205
  36. package/src/skills/sonamu-api/SKILL.md +0 -480
  37. package/src/skills/sonamu-auth/SKILL.md +0 -327
  38. package/src/skills/sonamu-auth/references/plugins.md +0 -310
  39. package/src/skills/sonamu-auth/references/user-id-migration-followups.md +0 -192
  40. package/src/skills/sonamu-auth/references/user-id-migration.md +0 -455
  41. package/src/skills/sonamu-config/SKILL.md +0 -203
  42. package/src/skills/sonamu-config/references/database.md +0 -452
  43. package/src/skills/sonamu-config/references/environments.md +0 -178
  44. package/src/skills/sonamu-config/references/server-options.md +0 -400
  45. package/src/skills/sonamu-entity/SKILL.md +0 -180
  46. package/src/skills/sonamu-entity/references/creation-workflow.md +0 -581
  47. package/src/skills/sonamu-entity/references/design-guides.md +0 -243
  48. package/src/skills/sonamu-entity/references/field-types.md +0 -170
  49. package/src/skills/sonamu-entity/references/relations-detail.md +0 -245
  50. package/src/skills/sonamu-entity/references/relations.md +0 -463
  51. package/src/skills/sonamu-entity/references/subset.md +0 -156
  52. package/src/skills/sonamu-fixture/SKILL.md +0 -180
  53. package/src/skills/sonamu-fixture/references/cli-usage.md +0 -439
  54. package/src/skills/sonamu-fixture/references/cone.md +0 -298
  55. package/src/skills/sonamu-frontend/SKILL.md +0 -142
  56. package/src/skills/sonamu-frontend/references/components.md +0 -323
  57. package/src/skills/sonamu-frontend/references/examples.md +0 -64
  58. package/src/skills/sonamu-frontend/references/hooks.md +0 -273
  59. package/src/skills/sonamu-frontend/references/runtime.md +0 -165
  60. package/src/skills/sonamu-frontend/references/scaffolding.md +0 -439
  61. package/src/skills/sonamu-i18n/SKILL.md +0 -287
  62. package/src/skills/sonamu-migration/SKILL.md +0 -316
  63. package/src/skills/sonamu-naite/SKILL.md +0 -266
  64. package/src/skills/sonamu-query/SKILL.md +0 -48
  65. package/src/skills/sonamu-query/references/model-patterns.md +0 -390
  66. package/src/skills/sonamu-query/references/model.md +0 -366
  67. package/src/skills/sonamu-query/references/puri.md +0 -413
  68. package/src/skills/sonamu-query/references/search.md +0 -238
  69. package/src/skills/sonamu-query/references/upsert.md +0 -324
  70. package/src/skills/sonamu-tasks/SKILL.md +0 -236
  71. package/src/skills/sonamu-testing/SKILL.md +0 -251
  72. package/src/skills/sonamu-testing/references/devrunner.md +0 -405
  73. package/src/skills/sonamu-testing/references/helpers.md +0 -185
  74. package/src/skills/sonamu-testing/references/patterns.md +0 -263
  75. package/src/skills/sonamu-testing/references/pitfalls.md +0 -588
  76. package/src/skills/sonamu-testing/references/quick-start.md +0 -285
  77. package/src/skills/sonamu-testing/references/type-safety.md +0 -172
  78. package/src/skills/sonamu-testing/references/writing-plan.md +0 -375
  79. package/src/skills/sonamu-vector/SKILL.md +0 -222
@@ -1,185 +0,0 @@
1
- # Test Helpers
2
-
3
- ## Fixture
4
-
5
- ### createFixtureLoader
6
-
7
- ```typescript
8
- // api/src/testing/fixture.ts
9
- import { createFixtureLoader } from "sonamu/test";
10
- import { CompanyModel } from "../application/company/company.model";
11
- import { UserModel } from "../application/user/user.model";
12
-
13
- export const loadFixtures = createFixtureLoader({
14
- company01: async () => CompanyModel.findById("A", 1),
15
- user01: async () => UserModel.findById("A", 1),
16
- });
17
- ```
18
-
19
- ### Using in tests
20
-
21
- ```typescript
22
- import { loadFixtures } from "../../testing/fixture";
23
-
24
- test("update company info", async () => {
25
- const f0 = await loadFixtures(["company01"]);
26
-
27
- await CompanyModel.save([
28
- {
29
- ...f0.company01,
30
- name: "Updated Company",
31
- },
32
- ]);
33
-
34
- const f1 = await loadFixtures(["company01"]);
35
- expect(f1.company01.name).toBe("Updated Company");
36
- });
37
- ```
38
-
39
- ## Naite (Test Tracing System)
40
-
41
- **→ Detailed guide (key list, chaining filters, wildcard, del, internal structure): `sonamu-naite`**
42
-
43
- Naite is a tracing system that records values with `Naite.t("key", value)` in source code and validates them with `Naite.get("key")` in tests.
44
-
45
- ### Commonly Used Patterns in Tests
46
-
47
- ```typescript
48
- import { Naite } from "sonamu";
49
-
50
- // Query validation
51
- expect(Naite.get("esq-query").first()).not.contain("limit");
52
-
53
- // UpsertBuilder behavior validation
54
- const trace = Naite.get("puri:ub-upserted").first();
55
- expect(trace).toMatchObject({ tableName: "users", rowCount: 3 });
56
-
57
- // Fetch methods: .first(), .last(), .at(n), .result() (full array)
58
- // Filters: .fromFile("user.model.ts"), .fromFunction("findById"), .where("data.tableName", "=", "users")
59
- ```
60
-
61
-
62
- ## Test Helper: expectQuery
63
-
64
- Helper for validating specific parts of SQL queries (see miomock for reference):
65
-
66
- ```typescript
67
- // api/src/testing/expect-query.ts
68
- import { type AST, Parser } from "node-sql-parser";
69
- import { expect } from "vitest";
70
-
71
- export type QueryPart =
72
- | "type"
73
- | "table"
74
- | "columns"
75
- | "set"
76
- | "where"
77
- | "join"
78
- | "orderBy"
79
- | "pagination"
80
- | "groupBy"
81
- | "having";
82
-
83
- export function expectQuery(query: string, part?: QueryPart) {
84
- if (!part) return expect(query);
85
- const ast = parseQuery(query);
86
- const extractedSql = extractors[part](ast);
87
- return expect(extractedSql);
88
- }
89
- ```
90
-
91
- ### Usage Examples
92
-
93
- ```typescript
94
- import { expectQuery } from "../testing/expect-query";
95
-
96
- test("validate select query", async () => {
97
- const db = UserModel.getPuri("r");
98
- await db.table("users").select({ id: "users.id" });
99
- const query = Naite.get("puri:executed-query").first();
100
-
101
- expectQuery(query, "type").toBe("select");
102
- expectQuery(query, "table").toBe("users");
103
- expectQuery(query, "columns").toMatchInlineSnapshot(`""users"."id" AS \`id\`"`);
104
- });
105
-
106
- test("validate where condition", async () => {
107
- const db = UserModel.getPuri("r");
108
- await db.table("users").where("users.id", 1);
109
- const query = Naite.get("puri:executed-query").first();
110
-
111
- expectQuery(query, "where").toMatchInlineSnapshot(`""users"."id" = 1"`);
112
- });
113
-
114
- test("validate join", async () => {
115
- const db = UserModel.getPuri("r");
116
- await db.table("employees").leftJoin("departments", "employees.department_id", "departments.id");
117
- const query = Naite.get("puri:executed-query").first();
118
-
119
- expectQuery(query, "join").toMatchInlineSnapshot(
120
- `"LEFT JOIN departments ON "employees"."department_id" = "departments"."id""`,
121
- );
122
- });
123
- ```
124
-
125
- ## Test Helper: expectUB
126
-
127
- UpsertBuilder state validation helper (see miomock for reference):
128
-
129
- ```typescript
130
- // api/src/testing/expect-ub.ts
131
- import type { UpsertBuilder } from "sonamu";
132
- import { expect } from "vitest";
133
-
134
- export type UBPart =
135
- | "tables"
136
- | "hasTable"
137
- | "rowCount"
138
- | "rows"
139
- | "row"
140
- | "refs"
141
- | "uniquesMap"
142
- | "uniqueIndexes";
143
-
144
- export function expectUB<P extends UBPart>(
145
- ub: UpsertBuilder,
146
- part: P,
147
- tableName?: string,
148
- index?: number,
149
- ) {
150
- // ... implementation
151
- }
152
- ```
153
-
154
- ### Usage Examples
155
-
156
- ```typescript
157
- import { expectUB } from "../testing/expect-ub";
158
-
159
- test("validate UpsertBuilder state", async () => {
160
- const ub = new UpsertBuilder();
161
-
162
- // initial state
163
- expectUB(ub, "hasTable", "users").toBe(false);
164
- expectUB(ub, "tables").toEqual([]);
165
-
166
- // after register
167
- ub.register("users", {
168
- email: "test@test.com",
169
- username: "test",
170
- password: "pw",
171
- role: "normal",
172
- });
173
-
174
- expectUB(ub, "hasTable", "users").toBe(true);
175
- expectUB(ub, "rowCount", "users").toBe(1);
176
- expectUB(ub, "row", "users", 0).toMatchObject({
177
- email: "test@test.com",
178
- username: "test",
179
- });
180
-
181
- // confirm reset after upsert
182
- await ub.upsert(wdb, "users");
183
- expectUB(ub, "rowCount", "users").toBe(0);
184
- });
185
- ```
@@ -1,263 +0,0 @@
1
- # Test Patterns
2
-
3
- ## Enum Value Usage Rules
4
-
5
- **CRITICAL: Only use enum values defined in entity.json.**
6
-
7
- ### Rules
8
-
9
- 1. Check the exact value list for enum fields in entity.json
10
- 2. If possible, use TypeScript enum types from `sonamu.generated.ts` (type-safe)
11
- 3. Set valid enum values as defaults in test-helpers.ts
12
- 4. Do not use arbitrary strings
13
-
14
- ```typescript
15
- // WRONG: written based on guesses
16
- role: "user"; // entity.json defines it as "normal"
17
- status: "in_progress"; // entity.json defines it as "pending"
18
-
19
- // CORRECT: written after checking entity.json
20
- role: "normal"; // exact value from entity.json
21
- status: "pending"; // exact value from entity.json
22
-
23
- // BEST: use TypeScript enum
24
- import { UserRoleEnum } from "../sonamu.generated";
25
- role: UserRoleEnum.normal;
26
- ```
27
-
28
- **Core principle: entity.json is the Single Source of Truth.**
29
-
30
-
31
- ## Test Basic Patterns
32
-
33
- ### bootstrap
34
-
35
- `bootstrap(vi)` call required in all test files:
36
-
37
- ```typescript
38
- import { bootstrap, test } from "sonamu/test";
39
- import { describe, expect, vi } from "vitest";
40
-
41
- bootstrap(vi);
42
-
43
- describe("MyTest", () => {
44
- test("test case", async () => {
45
- // ...
46
- });
47
- });
48
- ```
49
-
50
- **bootstrap options:**
51
-
52
- ```typescript
53
- // Default: forTesting: true (fast, skips Syncer/Task)
54
- bootstrap(vi);
55
-
56
- // forTesting: false - full initialization (loads Syncer, Task, EntityManager, etc.)
57
- // Used in tests for migrator, syncer, template, etc.
58
- bootstrap(vi, { forTesting: false });
59
- ```
60
-
61
- ### test vs testAs
62
-
63
- ```typescript
64
- // Unauthenticated test - Context.user is null
65
- test("unauthenticated test", async () => {
66
- const me = await UserModel.me();
67
- expect(me).toBeNull();
68
- });
69
-
70
- // Authenticated test - Context.user is set
71
- import type { UserSubsetSS } from "../sonamu.generated";
72
-
73
- const adminUser: UserSubsetSS = {
74
- id: 1,
75
- created_at: new Date(),
76
- email: "admin@test.com",
77
- username: "admin",
78
- role: "admin",
79
- };
80
-
81
- testAs(adminUser, "admin permission test", async () => {
82
- const me = await UserModel.me();
83
- expect(me?.role).toBe("admin");
84
- });
85
- ```
86
-
87
- ### test.each
88
-
89
- ```typescript
90
- test.each([
91
- { input: "user@example.com", expected: true },
92
- { input: "invalid-email", expected: false },
93
- ])("email validation: $input → $expected", async ({ input, expected }) => {
94
- expect(validateEmail(input)).toBe(expected);
95
- });
96
- ```
97
-
98
-
99
- ## Mock Patterns
100
-
101
- ### setup-mocks.ts
102
-
103
- ```typescript
104
- // api/src/testing/setup-mocks.ts
105
- import { Naite } from "sonamu";
106
- import { vi } from "vitest";
107
-
108
- vi.mock("fs/promises", async (importOriginal) => {
109
- const actual = (await importOriginal()) as typeof import("fs/promises");
110
- return {
111
- ...actual,
112
- access: vi.fn((path, mode) => {
113
- // virtual file system check
114
- const vfs = Naite.get("mock:fs/promises:virtualFileSystem").result();
115
- if (vfs.some((v) => v === path)) {
116
- return Promise.resolve();
117
- }
118
- return actual.access(path, mode);
119
- }),
120
- writeFile: vi.fn((path, data) => {
121
- Naite.t("fs/promises:writeFile", { path, data });
122
- }),
123
- rm: vi.fn(async (path, options) => {
124
- Naite.t("fs/promises:rm", { path, options });
125
- return Promise.resolve();
126
- }),
127
- };
128
- });
129
- ```
130
-
131
- ### test-helpers.ts
132
-
133
- ```typescript
134
- // api/src/testing/test-helpers.ts
135
- import { Entity, EntityManager, type EntityJson } from "sonamu";
136
- import { vi } from "vitest";
137
-
138
- // Mocking EntityManager.get
139
- export function mockEntityManagerGet(
140
- targetEntityId: string,
141
- overrideCallback: (original: EntityJson) => EntityJson,
142
- ) {
143
- const originalEntityJson = EntityManager.get(targetEntityId).toJson();
144
- const originalGet = EntityManager.get;
145
- return vi.spyOn(EntityManager, "get").mockImplementation((entityId) => {
146
- if (entityId === targetEntityId) {
147
- return new Entity(overrideCallback(originalEntityJson));
148
- }
149
- return originalGet.call(EntityManager, entityId);
150
- });
151
- }
152
- ```
153
-
154
- ## CRUD Test Patterns
155
-
156
- ### Create & Read
157
-
158
- ```typescript
159
- test("Create - create new user", async () => {
160
- const [userId] = await UserModel.save([
161
- {
162
- email: "newuser@test.com",
163
- username: "newuser",
164
- password: "hashedpassword",
165
- role: "normal",
166
- },
167
- ]);
168
-
169
- expect(userId).toBeGreaterThan(0);
170
-
171
- const user = await UserModel.findById("A", userId);
172
- expect(user.email).toBe("newuser@test.com");
173
- });
174
- ```
175
-
176
- ### Update
177
-
178
- ```typescript
179
- test("Update - update user", async () => {
180
- const f0 = await loadFixtures(["user01"]);
181
-
182
- await UserModel.save([
183
- {
184
- ...f0.user01,
185
- username: "updated_username",
186
- },
187
- ]);
188
-
189
- const f1 = await loadFixtures(["user01"]);
190
- expect(f1.user01.username).toBe("updated_username");
191
- });
192
- ```
193
-
194
- ### Error Tests
195
-
196
- ```typescript
197
- test("error when fetching non-existent user", async () => {
198
- await expect(UserModel.findById("A", 99999)).rejects.toThrow("not found");
199
- });
200
-
201
- test("unresolved reference error", async () => {
202
- const ub = new UpsertBuilder();
203
- const companyRef = ub.register("companies", { name: "Test" });
204
- ub.register("departments", { company_id: companyRef, name: "Dept" });
205
-
206
- // attempt upsert in wrong order
207
- await expect(ub.upsert(wdb, "departments")).rejects.toThrow(/unresolved reference/);
208
- });
209
- ```
210
-
211
- ## Test Structuring Patterns
212
-
213
- ```typescript
214
- describe("UpsertBuilder", () => {
215
- describe("A. Basic registration (register)", () => {
216
- test("register() returns UBRef", async () => {
217
- /* ... */
218
- });
219
- test("multiple register() calls accumulate rows", async () => {
220
- /* ... */
221
- });
222
- });
223
-
224
- describe("B. Table management", () => {
225
- test("basic behavior of getTable()/hasTable()", async () => {
226
- /* ... */
227
- });
228
- });
229
-
230
- describe("C. Upsert execution", () => {
231
- test("upsert() - insert new row", async () => {
232
- /* ... */
233
- });
234
- test("upsert() - update existing row", async () => {
235
- /* ... */
236
- });
237
- test("insertOnly() - insert only", async () => {
238
- /* ... */
239
- });
240
- });
241
-
242
- describe("D. Error handling", () => {
243
- test("upsert on non-existent table → empty array", async () => {
244
- /* ... */
245
- });
246
- test("unresolved reference → error", async () => {
247
- /* ... */
248
- });
249
- });
250
- });
251
- ```
252
-
253
- ## File Structure
254
-
255
- ```
256
- api/src/testing/
257
- ├── fixture.ts # createFixtureLoader definition
258
- ├── global.ts # globalSetup (dotenv, setup export)
259
- ├── setup-mocks.ts # global Mock configuration
260
- ├── test-helpers.ts # test utility functions
261
- ├── expect-query.ts # SQL query validation helper
262
- └── expect-ub.ts # UpsertBuilder validation helper
263
- ```