hikoutei 0.6.0 → 0.7.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/README.ja.md +37 -18
- package/README.ko.md +36 -18
- package/README.md +73 -31
- package/dist/adapter/persistence/contracts/scalar.d.ts +62 -12
- package/dist/adapter/persistence/contracts/scalar.d.ts.map +1 -1
- package/dist/adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.d.ts +5 -1
- package/dist/adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.d.ts.map +1 -1
- package/dist/adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.js +83 -7
- package/dist/adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.js.map +1 -1
- package/dist/api/EntityManager.d.ts +6 -7
- package/dist/api/EntityManager.d.ts.map +1 -1
- package/dist/api/errors.d.ts +2 -0
- package/dist/api/errors.d.ts.map +1 -1
- package/dist/api/errors.js +2 -0
- package/dist/api/errors.js.map +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js.map +1 -1
- package/dist/api/internalEntityManager.d.ts.map +1 -1
- package/dist/api/internalEntityManager.js +54 -65
- package/dist/api/internalEntityManager.js.map +1 -1
- package/dist/api/query.d.ts +62 -0
- package/dist/api/query.d.ts.map +1 -0
- package/dist/api/query.js +18 -0
- package/dist/api/query.js.map +1 -0
- package/dist/api/queryNormalization.d.ts +7 -0
- package/dist/api/queryNormalization.d.ts.map +1 -0
- package/dist/api/queryNormalization.js +262 -0
- package/dist/api/queryNormalization.js.map +1 -0
- package/dist/internal/syncStatus.d.ts +111 -0
- package/dist/internal/syncStatus.d.ts.map +1 -0
- package/dist/internal/syncStatus.js +265 -0
- package/dist/internal/syncStatus.js.map +1 -0
- package/package.json +5 -1
package/README.ja.md
CHANGED
|
@@ -215,41 +215,60 @@ MikroORM は実装の詳細であり、Hikoutei の公開エンティティ API
|
|
|
215
215
|
- スキーマ変更・手動編集・競合更新には、依然としてアプリケーションの運用
|
|
216
216
|
ポリシーが必要です。
|
|
217
217
|
|
|
218
|
+
## ローカルクエリ
|
|
219
|
+
|
|
220
|
+
読み取りは Hikoutei 独自の型付き演算子を使い、常に SQLite で実行されます。
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
const [users, total] = await em.findAndCount(
|
|
224
|
+
User,
|
|
225
|
+
{
|
|
226
|
+
name: { like: "Ada%" },
|
|
227
|
+
age: { gte: 18, lt: 65 },
|
|
228
|
+
active: { in: [true] },
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
orderBy: { age: "desc", name: "asc" },
|
|
232
|
+
limit: 20,
|
|
233
|
+
offset: 0,
|
|
234
|
+
},
|
|
235
|
+
);
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
`eq`、`ne`、`gt`、`gte`、`lt`、`lte`、`in`、`nin` は、宣言された
|
|
239
|
+
スカラー型で有効な範囲で利用でき、`like` は文字列専用です。
|
|
240
|
+
`{ active: true }` のような等価条件の省略記法も引き続き利用できます。
|
|
241
|
+
`count()` はページネーション前のフィルター総数を返し、`findAndCount()` は
|
|
242
|
+
1 つの SQLite スナップショットからページと総数を読み取ります。明示的な
|
|
243
|
+
並び順には最後のタイブレーカーとして主キーが追加され、`orderBy` のない
|
|
244
|
+
ページネーションは主キーの昇順を使用します。
|
|
245
|
+
|
|
218
246
|
## プロジェクトステータス
|
|
219
247
|
|
|
220
248
|
Hikoutei は活発に開発中です。現在の EntityManager は、スカラーエンティティの
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
`hikoutei setup` CLI がスプレッドシートとサービスアカウントをプロビジョニ
|
|
226
|
-
ングし、direct Google Sheets API provider(環境変数による自動開始)が唯一の
|
|
227
|
-
同期経路です — Apps Script ゲートウェイはありません。シート編集の取り込みと
|
|
249
|
+
ライフサイクル操作、型付きローカルフィルターと並び順、`limit` / `offset`
|
|
250
|
+
ページネーション、`count()`、スナップショット整合性のある `findAndCount()`、
|
|
251
|
+
コールバック形式の `transactional()` をサポートします。通常の読み取り元は
|
|
252
|
+
常に SQLite であり、Google Sheets ではありません。シート編集の取り込みと
|
|
228
253
|
競合表示はまだ発展途上です。マイナーバージョンのアップグレード前にリリース
|
|
229
254
|
ノートを確認してください。
|
|
230
255
|
|
|
231
256
|
## ロードマップ
|
|
232
257
|
|
|
233
|
-
EntityManager
|
|
234
|
-
|
|
258
|
+
最初の EntityManager 段階である豊富なローカル読み取りは完了しました。残る段階は
|
|
259
|
+
以下の実装順序に従い、日付やリリース番号は約束しません。
|
|
235
260
|
|
|
236
|
-
1.
|
|
237
|
-
- Hikoutei 独自の型付きクエリ契約に、明示的な `eq`、`ne`、`gt`、
|
|
238
|
-
`gte`、`lt`、`lte`、`in`、`nin`、`like` 条件と `orderBy`、
|
|
239
|
-
`count()`、`findAndCount()` を追加します。
|
|
240
|
-
- MikroORM のクエリ型を公開せず、これらを既存の `limit` / `offset`
|
|
241
|
-
ページネーションと組み合わせます。
|
|
242
|
-
2. **ライフサイクル安全な書き込み**
|
|
261
|
+
1. **ライフサイクル安全な書き込み**
|
|
243
262
|
- `upsert` と direct/bulk mutation 機能は、エンティティテーブル、
|
|
244
263
|
canonical state、永続的な Sheet effect outbox を 1 つの SQLite
|
|
245
264
|
トランザクションで処理する Hikoutei 独自の契約を通じてのみ追加します。
|
|
246
265
|
- この原子的なライフサイクルを迂回し得る、生の `nativeInsert`、
|
|
247
266
|
`nativeUpdate`、`nativeDelete`、または SQL パススルー API は約束しません。
|
|
248
|
-
|
|
267
|
+
2. **リレーションとロード**
|
|
249
268
|
- many-to-one、one-to-many、`populate()` 機能を追加します。
|
|
250
269
|
- 公開前に、リレーションの SQLite マッピング、Sheets プロジェクション
|
|
251
270
|
表現、スキーマ動作、競合セマンティクスを一体として設計します。
|
|
252
|
-
|
|
271
|
+
3. **スキーマ運用**
|
|
253
272
|
- マイグレーションとスキーマドリフト管理を追加します。
|
|
254
273
|
- 検証と運用フローを既存のセットアップツールと統合します。
|
|
255
274
|
|
package/README.ko.md
CHANGED
|
@@ -208,39 +208,57 @@ MikroORM은 구현 세부 사항이며 Hikoutei의 공개 엔티티 API에는
|
|
|
208
208
|
- 스키마 변경, 수동 편집, 충돌 업데이트에는 여전히 애플리케이션의 운영 정책이
|
|
209
209
|
필요합니다.
|
|
210
210
|
|
|
211
|
+
## 로컬 쿼리
|
|
212
|
+
|
|
213
|
+
읽기는 Hikoutei가 정의한 타입 연산자를 사용하며 항상 SQLite에서 실행됩니다.
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
const [users, total] = await em.findAndCount(
|
|
217
|
+
User,
|
|
218
|
+
{
|
|
219
|
+
name: { like: "Ada%" },
|
|
220
|
+
age: { gte: 18, lt: 65 },
|
|
221
|
+
active: { in: [true] },
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
orderBy: { age: "desc", name: "asc" },
|
|
225
|
+
limit: 20,
|
|
226
|
+
offset: 0,
|
|
227
|
+
},
|
|
228
|
+
);
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`은 선언된 스칼라 타입에
|
|
232
|
+
허용되는 범위에서 사용할 수 있고, `like`는 문자열 전용입니다. `{ active: true }`
|
|
233
|
+
같은 동등 조건 축약도 계속 지원합니다. `count()`는 페이지네이션 전 필터 전체 개수를
|
|
234
|
+
반환하고, `findAndCount()`는 한 SQLite 스냅샷에서 페이지와 전체 개수를 읽습니다.
|
|
235
|
+
명시적 정렬에는 마지막 동률 해소 기준으로 PK가 추가되며, `orderBy` 없는
|
|
236
|
+
페이지네이션은 PK 오름차순을 사용합니다.
|
|
237
|
+
|
|
211
238
|
## 프로젝트 상태
|
|
212
239
|
|
|
213
|
-
Hikoutei는 활발히 개발 중입니다. 현재 EntityManager는 스칼라
|
|
214
|
-
|
|
215
|
-
`
|
|
216
|
-
Google Sheets가 아니라 항상 SQLite에서 수행됩니다.
|
|
217
|
-
스프레드시트와 서비스 계정을 프로비저닝하며, direct Google Sheets API
|
|
218
|
-
provider(환경 변수 자동 시작)가 유일한 sync 경로입니다 — Apps Script
|
|
219
|
-
gateway가 없습니다. 시트 편집 수집과 충돌 표시는
|
|
240
|
+
Hikoutei는 활발히 개발 중입니다. 현재 EntityManager는 스칼라 엔티티 생명주기,
|
|
241
|
+
타입 로컬 필터와 정렬, `limit` / `offset` 페이지네이션, `count()`, 스냅샷이
|
|
242
|
+
일관된 `findAndCount()`, 콜백형 `transactional()`을 지원합니다. 일반 읽기는
|
|
243
|
+
Google Sheets가 아니라 항상 SQLite에서 수행됩니다. 시트 편집 수집과 충돌 표시는
|
|
220
244
|
아직 발전 중입니다. 마이너 버전 업그레이드 전에 릴리스 노트를 확인하세요.
|
|
221
245
|
|
|
222
246
|
## 로드맵
|
|
223
247
|
|
|
224
|
-
EntityManager
|
|
225
|
-
일정이나 릴리스 번호는 약속하지 않습니다.
|
|
248
|
+
첫 EntityManager 단계인 풍부한 로컬 읽기는 완료됐습니다. 남은 단계는 아래 구현
|
|
249
|
+
순서를 따르며, 일정이나 릴리스 번호는 약속하지 않습니다.
|
|
226
250
|
|
|
227
|
-
1.
|
|
228
|
-
- Hikoutei가 정의한 타입 쿼리 계약에 명시적 `eq`, `ne`, `gt`, `gte`,
|
|
229
|
-
`lt`, `lte`, `in`, `nin`, `like` 조건과 `orderBy`, `count()`,
|
|
230
|
-
`findAndCount()`를 추가합니다.
|
|
231
|
-
- MikroORM 쿼리 타입을 노출하지 않고 이 기능들을 기존 `limit` / `offset`
|
|
232
|
-
페이지네이션과 조합합니다.
|
|
233
|
-
2. **생명주기 안전 쓰기**
|
|
251
|
+
1. **생명주기 안전 쓰기**
|
|
234
252
|
- `upsert`와 direct/bulk mutation 기능은 엔티티 테이블, canonical state,
|
|
235
253
|
내구성 있는 Sheet effect outbox를 하나의 SQLite 트랜잭션에서 처리하는
|
|
236
254
|
Hikoutei 정의 계약을 통해서만 추가합니다.
|
|
237
255
|
- 이 원자적 생명주기를 우회할 수 있는 원시 `nativeInsert`, `nativeUpdate`,
|
|
238
256
|
`nativeDelete` 또는 SQL 패스스루 API는 약속하지 않습니다.
|
|
239
|
-
|
|
257
|
+
2. **관계와 로딩**
|
|
240
258
|
- many-to-one, one-to-many, `populate()` 기능을 추가합니다.
|
|
241
259
|
- 공개 전에 관계의 SQLite 매핑, Sheets 프로젝션 표현, 스키마 동작, 충돌
|
|
242
260
|
의미론을 함께 설계합니다.
|
|
243
|
-
|
|
261
|
+
3. **스키마 운영**
|
|
244
262
|
- 마이그레이션과 스키마 드리프트 관리를 추가합니다.
|
|
245
263
|
- 검증 및 운영 흐름을 기존 설정 도구와 통합합니다.
|
|
246
264
|
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ changes are asynchronously projected to Google Sheets for human review and
|
|
|
12
12
|
lightweight collaboration.
|
|
13
13
|
|
|
14
14
|
<a href="https://www.npmjs.com/package/hikoutei">npm</a> ·
|
|
15
|
-
<a href="
|
|
15
|
+
<a href="website/guide/quick-start.md">Quick start</a> ·
|
|
16
16
|
<a href="https://github.com/ManddarinShop/Hikoutei/issues">Issues</a>
|
|
17
17
|
|
|
18
18
|
[](https://www.npmjs.com/package/hikoutei)
|
|
@@ -48,6 +48,8 @@ const User = defineTypedSheetsEntity({
|
|
|
48
48
|
properties: {
|
|
49
49
|
id: { type: "string", primary: true },
|
|
50
50
|
name: { type: "string" },
|
|
51
|
+
age: { type: "number" },
|
|
52
|
+
active: { type: "boolean" },
|
|
51
53
|
},
|
|
52
54
|
});
|
|
53
55
|
|
|
@@ -57,7 +59,7 @@ const hikoutei = await createTypedSheets({
|
|
|
57
59
|
});
|
|
58
60
|
|
|
59
61
|
const em = hikoutei.em.fork();
|
|
60
|
-
const user = em.create(User, { id: "u1", name: "Ada" });
|
|
62
|
+
const user = em.create(User, { id: "u1", name: "Ada", age: 36, active: true });
|
|
61
63
|
em.persist(user);
|
|
62
64
|
await em.flush();
|
|
63
65
|
|
|
@@ -257,12 +259,12 @@ Hikoutei uses a durable local outbox, idempotent delivery, and conflict-aware
|
|
|
257
259
|
updates so temporary API failures do not lose committed application writes. The
|
|
258
260
|
provider never logs credentials, spreadsheet IDs, URLs, or payloads, and it
|
|
259
261
|
spaces request starts to stay inside Google's quota windows. See the
|
|
260
|
-
[internal consistency model](
|
|
262
|
+
[internal consistency model](website/guide/internal-consistency.md) for the
|
|
261
263
|
detailed state machine and recovery rules.
|
|
262
264
|
|
|
263
265
|
Live Google calls are opt-in; fake providers and SQLite fixtures are the normal
|
|
264
266
|
verification path. The detailed setup and troubleshooting steps are in the
|
|
265
|
-
[Quick start](
|
|
267
|
+
[Quick start](website/guide/quick-start.md).
|
|
266
268
|
|
|
267
269
|
## Installation
|
|
268
270
|
|
|
@@ -278,16 +280,18 @@ entity API.
|
|
|
278
280
|
|
|
279
281
|
## Documentation
|
|
280
282
|
|
|
281
|
-
- [Quick start](
|
|
282
|
-
-
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
- [Quick start](website/guide/quick-start.md) — installation, ORM lifecycle,
|
|
284
|
+
and service-side sync setup.
|
|
285
|
+
- [Architecture](website/guide/architecture.md) — how the local store and
|
|
286
|
+
Sheet views fit together.
|
|
287
|
+
- [Write and synchronization flow](website/guide/sync-flow.md) —
|
|
285
288
|
asynchronous delivery and recovery behavior.
|
|
286
|
-
- [Internal consistency model](
|
|
287
|
-
outbox, idempotent delivery, and conflict-aware updates.
|
|
288
|
-
- [
|
|
289
|
-
|
|
290
|
-
|
|
289
|
+
- [Internal consistency model](website/guide/internal-consistency.md) —
|
|
290
|
+
durable outbox, idempotent delivery, and conflict-aware updates.
|
|
291
|
+
- [Contributing](website/guide/contributing.md) — local development and test
|
|
292
|
+
commands.
|
|
293
|
+
- [Benchmark notes](website/guide/benchmarks.md) — dated measurements and
|
|
294
|
+
their limitations.
|
|
291
295
|
|
|
292
296
|
## Limitations
|
|
293
297
|
|
|
@@ -296,41 +300,79 @@ entity API.
|
|
|
296
300
|
- SQLite is local to the service and is not a distributed coordination layer.
|
|
297
301
|
- Schema changes, manual edits, and conflicting updates still need an
|
|
298
302
|
operational policy from the application.
|
|
303
|
+
- The EntityManager is an ORM-style facade over scalar entities, not a full
|
|
304
|
+
ORM: entity definitions are scalar-only (`string`, `number`, `boolean`,
|
|
305
|
+
`date`), and v1 permits uniqueness only on the primary/business key.
|
|
306
|
+
- Relations, joins, `populate()`, migrations, cascades, bulk/ORM query
|
|
307
|
+
builders, and raw SQL are unsupported in this milestone. Sheets is an async
|
|
308
|
+
projection and human input surface, never a live query database.
|
|
309
|
+
|
|
310
|
+
## Local queries
|
|
311
|
+
|
|
312
|
+
Reads use Hikoutei-owned typed operators and always execute against SQLite:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
const [users, total] = await em.findAndCount(
|
|
316
|
+
User,
|
|
317
|
+
{
|
|
318
|
+
name: { like: "Ada%" },
|
|
319
|
+
age: { gte: 18, lt: 65 },
|
|
320
|
+
active: { in: [true] },
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
orderBy: { age: "desc", name: "asc" },
|
|
324
|
+
limit: 20,
|
|
325
|
+
offset: 0,
|
|
326
|
+
},
|
|
327
|
+
);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
`eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, and `nin` are available where
|
|
331
|
+
valid for the declared scalar type; `like` is string-only. Equality shorthand
|
|
332
|
+
such as `{ active: true }` remains supported. `count()` returns the unpaged
|
|
333
|
+
filter total, and `findAndCount()` returns the filtered page plus a total
|
|
334
|
+
that ignores `limit`/`offset` — both read from one SQLite snapshot. When an
|
|
335
|
+
explicit `orderBy` omits the primary key, Hikoutei appends it in ascending
|
|
336
|
+
order as the final tie-breaker; when the primary key is explicitly ordered,
|
|
337
|
+
its supplied position and direction are preserved. Pagination without
|
|
338
|
+
`orderBy` uses primary-key ascending order.
|
|
339
|
+
|
|
340
|
+
An `offset` alone (no `limit`) is a valid offset-only read, and an explicit
|
|
341
|
+
`limit: 0` returns an empty page rather than being treated as "no limit".
|
|
342
|
+
`findOne()` returns one entity or `null` and accepts ordering but no paging
|
|
343
|
+
options. Malformed filters, operators, ordering, and paging options fail with
|
|
344
|
+
a stable `HikouteiError`; branch on `error.code` through the exported
|
|
345
|
+
`HIKOUTEI_ERROR_CODES` constants (`HIKOUTEI_ERROR_CODES.INVALID_QUERY` and
|
|
346
|
+
`HIKOUTEI_ERROR_CODES.INVALID_SCALAR_VALUE`, which resolve to the lowercase
|
|
347
|
+
runtime codes `invalid_query` and `invalid_scalar_value`) instead of guessing
|
|
348
|
+
strings or parsing messages.
|
|
299
349
|
|
|
300
350
|
## Project status
|
|
301
351
|
|
|
302
352
|
Hikoutei is in active development. The current EntityManager supports scalar
|
|
303
|
-
entity lifecycle operations,
|
|
304
|
-
`
|
|
305
|
-
`transactional()` work.
|
|
306
|
-
|
|
307
|
-
setup` CLI provisions the spreadsheet and service account, and the direct
|
|
308
|
-
Google Sheets API provider (env-driven auto-start) is the only sync path — no
|
|
309
|
-
Apps Script gateway. Sheet edit ingestion and conflict presentation are still
|
|
353
|
+
entity lifecycle operations, typed local filters and ordering, `limit` /
|
|
354
|
+
`offset` pagination, `count()`, snapshot-consistent `findAndCount()`, and
|
|
355
|
+
callback-style `transactional()` work. Normal reads always come from SQLite,
|
|
356
|
+
never Google Sheets. Sheet edit ingestion and conflict presentation are still
|
|
310
357
|
evolving. Review release notes before upgrading minor versions.
|
|
311
358
|
|
|
312
359
|
## Roadmap
|
|
313
360
|
|
|
314
|
-
The EntityManager
|
|
315
|
-
|
|
361
|
+
The first EntityManager milestone, rich local reads, is complete. Remaining
|
|
362
|
+
milestones follow the implementation order below; no milestone is tied to a
|
|
363
|
+
date or release number.
|
|
316
364
|
|
|
317
|
-
1. **
|
|
318
|
-
- Add a Hikoutei-owned typed query contract for explicit `eq`, `ne`, `gt`,
|
|
319
|
-
`gte`, `lt`, `lte`, `in`, `nin`, and `like` conditions, plus `orderBy`,
|
|
320
|
-
`count()`, and `findAndCount()`.
|
|
321
|
-
- Compose these capabilities with the existing `limit` / `offset`
|
|
322
|
-
pagination without exposing MikroORM query types.
|
|
323
|
-
2. **Lifecycle-safe writes**
|
|
365
|
+
1. **Lifecycle-safe writes**
|
|
324
366
|
- Add `upsert` and direct/bulk mutation capabilities only through a
|
|
325
367
|
Hikoutei-owned contract that preserves one SQLite transaction across the
|
|
326
368
|
entity table, canonical state, and durable Sheet effect outbox.
|
|
327
369
|
- Do not promise raw `nativeInsert`, `nativeUpdate`, `nativeDelete`, or SQL
|
|
328
370
|
pass-through APIs that could bypass that atomic lifecycle.
|
|
329
|
-
|
|
371
|
+
2. **Relationships and loading**
|
|
330
372
|
- Add many-to-one, one-to-many, and `populate()` capabilities.
|
|
331
373
|
- Design SQLite relationship mapping, Sheets projection representation,
|
|
332
374
|
schema behavior, and conflict semantics together before public release.
|
|
333
|
-
|
|
375
|
+
3. **Schema operations**
|
|
334
376
|
- Add migration and schema drift management.
|
|
335
377
|
- Integrate validation and operational workflows with the existing setup
|
|
336
378
|
tooling.
|
|
@@ -84,27 +84,79 @@ export interface ScalarEntityFlushContext {
|
|
|
84
84
|
export interface ScalarEntityFlushCoordinator {
|
|
85
85
|
onFlush(context: ScalarEntityFlushContext): Promise<void>;
|
|
86
86
|
}
|
|
87
|
-
/**
|
|
88
|
-
export interface
|
|
87
|
+
/** Non-null scalar comparison represented independently from any ORM syntax. */
|
|
88
|
+
export interface ScalarEntityComparisonPredicate {
|
|
89
|
+
readonly kind: "comparison";
|
|
90
|
+
readonly field: string;
|
|
91
|
+
readonly operator: "eq" | "ne" | "gt" | "gte" | "lt" | "lte";
|
|
92
|
+
readonly value: Exclude<ScalarEntityValue, null>;
|
|
93
|
+
}
|
|
94
|
+
/** Non-empty set membership predicate after public-array validation. */
|
|
95
|
+
export interface ScalarEntitySetPredicate {
|
|
96
|
+
readonly kind: "set";
|
|
97
|
+
readonly field: string;
|
|
98
|
+
readonly operator: "in" | "nin";
|
|
99
|
+
readonly values: readonly Exclude<ScalarEntityValue, null>[];
|
|
100
|
+
}
|
|
101
|
+
/** SQLite LIKE predicate over one validated string field and pattern. */
|
|
102
|
+
export interface ScalarEntityLikePredicate {
|
|
103
|
+
readonly kind: "like";
|
|
104
|
+
readonly field: string;
|
|
105
|
+
readonly pattern: string;
|
|
106
|
+
}
|
|
107
|
+
/** Explicit nullable-field predicate that avoids SQL three-valued ambiguity. */
|
|
108
|
+
export interface ScalarEntityNullPredicate {
|
|
109
|
+
readonly kind: "null";
|
|
110
|
+
readonly field: string;
|
|
111
|
+
readonly operator: "is_null" | "is_not_null";
|
|
112
|
+
}
|
|
113
|
+
/** Query constant produced by empty filters and empty membership sets. */
|
|
114
|
+
export interface ScalarEntityConstantPredicate {
|
|
115
|
+
readonly kind: "constant";
|
|
116
|
+
readonly value: boolean;
|
|
117
|
+
}
|
|
118
|
+
/** Internal logical group used only after public field filters are validated. */
|
|
119
|
+
export interface ScalarEntityPredicateGroup {
|
|
120
|
+
readonly kind: "all" | "any";
|
|
121
|
+
readonly predicates: readonly ScalarEntityPredicate[];
|
|
122
|
+
}
|
|
123
|
+
/** Provider-neutral query predicate promoted from the public filter boundary. */
|
|
124
|
+
export type ScalarEntityPredicate = ScalarEntityComparisonPredicate | ScalarEntitySetPredicate | ScalarEntityLikePredicate | ScalarEntityNullPredicate | ScalarEntityConstantPredicate | ScalarEntityPredicateGroup;
|
|
125
|
+
/** One normalized sort key in deterministic precedence order. */
|
|
126
|
+
export interface ScalarEntityOrder {
|
|
127
|
+
readonly field: string;
|
|
128
|
+
readonly direction: "asc" | "desc";
|
|
129
|
+
}
|
|
130
|
+
/** Validated filter shared by collection reads and count queries. */
|
|
131
|
+
export interface ScalarEntityCountQuery {
|
|
89
132
|
readonly tableName: string;
|
|
90
133
|
readonly primaryKeyColumn: string;
|
|
91
|
-
|
|
92
|
-
|
|
134
|
+
readonly predicate: ScalarEntityPredicate;
|
|
135
|
+
}
|
|
136
|
+
/** Validated filter, ordering, and paging for one scalar entity read. */
|
|
137
|
+
export interface ScalarEntityQuery extends ScalarEntityCountQuery {
|
|
138
|
+
readonly orderBy: readonly ScalarEntityOrder[];
|
|
93
139
|
readonly limit?: number;
|
|
94
140
|
readonly offset?: number;
|
|
95
141
|
}
|
|
142
|
+
/** One scalar entity row returned by a read. */
|
|
143
|
+
export type ScalarEntityRow = Readonly<Record<string, ScalarEntityValue>>;
|
|
144
|
+
/** Read operations available both outside and inside provider transactions. */
|
|
145
|
+
export interface ScalarEntityReader {
|
|
146
|
+
read(query: ScalarEntityQuery): Promise<readonly ScalarEntityRow[]>;
|
|
147
|
+
/** Returns the unpaged number of rows matching the query predicate. */
|
|
148
|
+
count(query: ScalarEntityCountQuery): Promise<number>;
|
|
149
|
+
}
|
|
96
150
|
/**
|
|
97
151
|
* Write surface available inside one atomic transaction.
|
|
98
152
|
*
|
|
99
153
|
* Inserts, updates, and deletes run against the active transaction so a single
|
|
100
154
|
* `flush()` either commits every entity row or rolls them all back.
|
|
101
155
|
*/
|
|
102
|
-
export interface ScalarEntityTransaction {
|
|
156
|
+
export interface ScalarEntityTransaction extends ScalarEntityReader {
|
|
103
157
|
insert(row: ScalarEntityInsert): Promise<void>;
|
|
104
158
|
update(row: ScalarEntityUpdate): Promise<void>;
|
|
105
159
|
delete(row: ScalarEntityDelete): Promise<void>;
|
|
106
|
-
/** Reads rows through the active transaction's view of the table. */
|
|
107
|
-
read(query: ScalarEntityQuery): Promise<readonly ScalarEntityRow[]>;
|
|
108
160
|
/**
|
|
109
161
|
* Flushes provider-scheduled entity, canonical-state, and outbox work before
|
|
110
162
|
* the common UoW advances snapshots. The enclosing transaction must still be
|
|
@@ -112,8 +164,6 @@ export interface ScalarEntityTransaction {
|
|
|
112
164
|
*/
|
|
113
165
|
flush(): Promise<void>;
|
|
114
166
|
}
|
|
115
|
-
/** One scalar entity row returned by a read. */
|
|
116
|
-
export type ScalarEntityRow = Readonly<Record<string, ScalarEntityValue>>;
|
|
117
167
|
/**
|
|
118
168
|
* Replaceable local persistence engine behind the public EntityManager.
|
|
119
169
|
*
|
|
@@ -122,11 +172,11 @@ export type ScalarEntityRow = Readonly<Record<string, ScalarEntityValue>>;
|
|
|
122
172
|
* callback within one SQLite transaction and roll the whole callback back when
|
|
123
173
|
* it rejects.
|
|
124
174
|
*/
|
|
125
|
-
export interface ScalarEntityPersistenceProvider {
|
|
175
|
+
export interface ScalarEntityPersistenceProvider extends ScalarEntityReader {
|
|
126
176
|
/** Runs one atomic transaction and rolls back every write on rejection. */
|
|
127
177
|
beginTransaction<Result>(work: (transaction: ScalarEntityTransaction) => Promise<Result>): Promise<Result>;
|
|
128
|
-
/**
|
|
129
|
-
|
|
178
|
+
/** Runs read operations against one consistent persistence snapshot. */
|
|
179
|
+
readSnapshot<Result>(work: (reader: ScalarEntityReader) => Promise<Result>): Promise<Result>;
|
|
130
180
|
/** Releases resources owned by the underlying SQLite connection. */
|
|
131
181
|
close(): Promise<void>;
|
|
132
182
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scalar.d.ts","sourceRoot":"","sources":["../../../../src/adapter/persistence/contracts/scalar.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"scalar.d.ts","sourceRoot":"","sources":["../../../../src/adapter/persistence/contracts/scalar.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* entity statements in the same SQLite transaction.
|
|
8
8
|
*/
|
|
9
9
|
import type { ResolvedHikouteiEntityDescriptor } from "../../../../../api/entity.js";
|
|
10
|
-
import type { ScalarEntityFlushCoordinator, ScalarEntityPersistenceProvider, ScalarEntityQuery, ScalarEntityRow, ScalarEntityTransaction } from "../../../contracts/scalar.js";
|
|
10
|
+
import type { ScalarEntityCountQuery, ScalarEntityFlushCoordinator, ScalarEntityPersistenceProvider, ScalarEntityQuery, ScalarEntityReader, ScalarEntityRow, ScalarEntityTransaction } from "../../../contracts/scalar.js";
|
|
11
11
|
import type { MikroOrmSqliteAdapter } from "../storage/MikroOrmSqliteAdapter.js";
|
|
12
12
|
import type { MappedEntityReference } from "../../../../../application/orm/mapping/contracts.js";
|
|
13
13
|
/** Internal mapping from a public descriptor to its generated MikroORM entity. */
|
|
@@ -29,6 +29,10 @@ export declare class MikroOrmScalarPersistenceProvider implements ScalarEntityPe
|
|
|
29
29
|
constructor(storage: MikroOrmSqliteAdapter, bindings: readonly MikroOrmScalarEntityBinding[], flushCoordinator?: ScalarEntityFlushCoordinator | undefined);
|
|
30
30
|
/** Reads through a clean manager without flushing another Unit of Work. */
|
|
31
31
|
read(query: ScalarEntityQuery): Promise<readonly ScalarEntityRow[]>;
|
|
32
|
+
/** Counts rows through a clean manager without materializing entities. */
|
|
33
|
+
count(query: ScalarEntityCountQuery): Promise<number>;
|
|
34
|
+
/** Runs sequential reads through one consistent SQLite read transaction. */
|
|
35
|
+
readSnapshot<Result>(work: (reader: ScalarEntityReader) => Promise<Result>): Promise<Result>;
|
|
32
36
|
/** Runs the common UoW plan and mapped work in one SQLite transaction. */
|
|
33
37
|
beginTransaction<Result>(work: (transaction: ScalarEntityTransaction) => Promise<Result>): Promise<Result>;
|
|
34
38
|
/** Closes the one SQLite connection owned by this provider. */
|
package/dist/adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MikroOrmScalarPersistenceProvider.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAErF,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"MikroOrmScalarPersistenceProvider.d.ts","sourceRoot":"","sources":["../../../../../../src/adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,8BAA8B,CAAC;AAErF,OAAO,KAAK,EACV,sBAAsB,EAGtB,4BAA4B,EAE5B,+BAA+B,EAE/B,iBAAiB,EACjB,kBAAkB,EAClB,eAAe,EACf,uBAAuB,EAGxB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EACV,qBAAqB,EAEtB,MAAM,qCAAqC,CAAC;AAG7C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qDAAqD,CAAC;AAEjG,kFAAkF;AAClF,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,UAAU,EAAE,gCAAgC,CAAC;IACtD,uEAAuE;IACvE,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACjE;AAED;;;;GAIG;AACH,qBAAa,iCAAkC,YAAW,+BAA+B;IAKrF,OAAO,CAAC,QAAQ,CAAC,OAAO;IAExB,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IANpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmD;IAC5E,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAmD;gBAGhE,OAAO,EAAE,qBAAqB,EAC/C,QAAQ,EAAE,SAAS,2BAA2B,EAAE,EAC/B,gBAAgB,CAAC,EAAE,4BAA4B,YAAA;IAMlE,2EAA2E;IACrE,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,SAAS,eAAe,EAAE,CAAC;IAKzE,0EAA0E;IACpE,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC;IAK3D,4EAA4E;IACtE,YAAY,CAAC,MAAM,EACvB,IAAI,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,OAAO,CAAC,MAAM,CAAC,GACpD,OAAO,CAAC,MAAM,CAAC;IAUlB,0EAA0E;IACpE,gBAAgB,CAAC,MAAM,EAC3B,IAAI,EAAE,CAAC,WAAW,EAAE,uBAAuB,KAAK,OAAO,CAAC,MAAM,CAAC,GAC9D,OAAO,CAAC,MAAM,CAAC;IAalB,+DAA+D;IACzD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,OAAO,CAAC,qBAAqB;CAK9B"}
|
package/dist/adapter/persistence/providers/mikro-orm/api/MikroOrmScalarPersistenceProvider.js
CHANGED
|
@@ -30,6 +30,17 @@ export class MikroOrmScalarPersistenceProvider {
|
|
|
30
30
|
const manager = this.storage.forkEntityManager();
|
|
31
31
|
return readRows(manager, this.requireBindingByTable(query.tableName), query);
|
|
32
32
|
}
|
|
33
|
+
/** Counts rows through a clean manager without materializing entities. */
|
|
34
|
+
async count(query) {
|
|
35
|
+
const manager = this.storage.forkEntityManager();
|
|
36
|
+
return countRows(manager, this.requireBindingByTable(query.tableName), query);
|
|
37
|
+
}
|
|
38
|
+
/** Runs sequential reads through one consistent SQLite read transaction. */
|
|
39
|
+
async readSnapshot(work) {
|
|
40
|
+
return this.storage.transactional(async ({ entityManager }) => {
|
|
41
|
+
return work(new MikroOrmScalarReader(entityManager, this.bindings, this.bindingsByTable));
|
|
42
|
+
});
|
|
43
|
+
}
|
|
33
44
|
/** Runs the common UoW plan and mapped work in one SQLite transaction. */
|
|
34
45
|
async beginTransaction(work) {
|
|
35
46
|
return this.storage.transactional(async ({ entityManager }) => {
|
|
@@ -61,6 +72,9 @@ class MikroOrmScalarReader {
|
|
|
61
72
|
async read(query) {
|
|
62
73
|
return readRows(this.entityManager, this.requireBindingByTable(query.tableName), query);
|
|
63
74
|
}
|
|
75
|
+
async count(query) {
|
|
76
|
+
return countRows(this.entityManager, this.requireBindingByTable(query.tableName), query);
|
|
77
|
+
}
|
|
64
78
|
requireBindingByTable(tableName) {
|
|
65
79
|
const binding = this.bindingsByTable.get(tableName);
|
|
66
80
|
if (binding !== undefined)
|
|
@@ -149,7 +163,7 @@ function createManagedEntity(entityManager, binding, values) {
|
|
|
149
163
|
async function readRows(entityManager, binding, query) {
|
|
150
164
|
const result = await Reflect.apply(entityManager.find, entityManager, [
|
|
151
165
|
binding.entity,
|
|
152
|
-
toMikroOrmFilter(binding.descriptor, query.
|
|
166
|
+
toMikroOrmFilter(toInternalPredicate(binding.descriptor, query.predicate), query.primaryKeyColumn),
|
|
153
167
|
toMikroOrmQueryOptions(query),
|
|
154
168
|
]);
|
|
155
169
|
if (!Array.isArray(result) || !result.every(isRecord)) {
|
|
@@ -157,17 +171,79 @@ async function readRows(entityManager, binding, query) {
|
|
|
157
171
|
}
|
|
158
172
|
return result.map((entity) => fromInternalEntity(binding.descriptor, entity));
|
|
159
173
|
}
|
|
174
|
+
async function countRows(entityManager, binding, query) {
|
|
175
|
+
const result = await Reflect.apply(entityManager.count, entityManager, [
|
|
176
|
+
binding.entity,
|
|
177
|
+
toMikroOrmFilter(toInternalPredicate(binding.descriptor, query.predicate), query.primaryKeyColumn),
|
|
178
|
+
]);
|
|
179
|
+
if (typeof result !== "number" || !Number.isSafeInteger(result) || result < 0) {
|
|
180
|
+
throw new HikouteiError(HIKOUTEI_ERROR_CODES.INVALID_SCALAR_VALUE, "MikroORM count result must be a non-negative safe integer.");
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
160
184
|
function toMikroOrmQueryOptions(query) {
|
|
185
|
+
const orderBy = query.orderBy.map((order) => ({ [order.field]: order.direction }));
|
|
186
|
+
// SQLite rejects a bare `OFFSET` (it requires a preceding `LIMIT`), so an
|
|
187
|
+
// offset-only public query must use the SQLite idiom for "all rows after a
|
|
188
|
+
// skip": a negative `LIMIT`, which SQLite treats as no upper bound. The
|
|
189
|
+
// public option contract still allows `{ offset }` independently of
|
|
190
|
+
// `{ limit }`; this `LIMIT -1` stays inside the MikroORM adapter boundary and
|
|
191
|
+
// is never exposed as raw SQL to application code. `limit` is `0`-safe via
|
|
192
|
+
// nullish coalescing: an explicit `limit: 0` is preserved unchanged.
|
|
193
|
+
const limit = query.limit ?? (query.offset === undefined ? undefined : -1);
|
|
161
194
|
return {
|
|
162
|
-
...(
|
|
195
|
+
...(orderBy.length === 0 ? {} : { orderBy }),
|
|
196
|
+
...(limit === undefined ? {} : { limit }),
|
|
163
197
|
...(query.offset === undefined ? {} : { offset: query.offset }),
|
|
164
198
|
};
|
|
165
199
|
}
|
|
166
|
-
function
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
200
|
+
function toInternalPredicate(descriptor, predicate) {
|
|
201
|
+
switch (predicate.kind) {
|
|
202
|
+
case "comparison":
|
|
203
|
+
return {
|
|
204
|
+
...predicate,
|
|
205
|
+
value: toInternalValue(descriptor, predicate.field, predicate.value),
|
|
206
|
+
};
|
|
207
|
+
case "set":
|
|
208
|
+
return {
|
|
209
|
+
...predicate,
|
|
210
|
+
values: predicate.values.map((value) => toInternalValue(descriptor, predicate.field, value)),
|
|
211
|
+
};
|
|
212
|
+
case "all":
|
|
213
|
+
case "any":
|
|
214
|
+
return {
|
|
215
|
+
...predicate,
|
|
216
|
+
predicates: predicate.predicates.map((child) => toInternalPredicate(descriptor, child)),
|
|
217
|
+
};
|
|
218
|
+
case "like":
|
|
219
|
+
case "null":
|
|
220
|
+
case "constant":
|
|
221
|
+
return predicate;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function toMikroOrmFilter(predicate, primaryKeyColumn) {
|
|
225
|
+
switch (predicate.kind) {
|
|
226
|
+
case "comparison":
|
|
227
|
+
return { [predicate.field]: { [`$${predicate.operator}`]: predicate.value } };
|
|
228
|
+
case "set":
|
|
229
|
+
return { [predicate.field]: { [`$${predicate.operator}`]: [...predicate.values] } };
|
|
230
|
+
case "like":
|
|
231
|
+
return { [predicate.field]: { $like: predicate.pattern } };
|
|
232
|
+
case "null":
|
|
233
|
+
return predicate.operator === "is_null"
|
|
234
|
+
? { [predicate.field]: null }
|
|
235
|
+
: { [predicate.field]: { $ne: null } };
|
|
236
|
+
case "constant":
|
|
237
|
+
return predicate.value ? {} : { [primaryKeyColumn]: { $in: [] } };
|
|
238
|
+
case "all":
|
|
239
|
+
return {
|
|
240
|
+
$and: predicate.predicates.map((child) => toMikroOrmFilter(child, primaryKeyColumn)),
|
|
241
|
+
};
|
|
242
|
+
case "any":
|
|
243
|
+
return {
|
|
244
|
+
$or: predicate.predicates.map((child) => toMikroOrmFilter(child, primaryKeyColumn)),
|
|
245
|
+
};
|
|
246
|
+
}
|
|
171
247
|
}
|
|
172
248
|
function toInternalData(descriptor, values) {
|
|
173
249
|
return Object.fromEntries(Object.entries(values).map(([property, value]) => [
|