@nest-batch/typeorm 0.2.1 → 0.2.2

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 (3) hide show
  1. package/README.ko.md +55 -0
  2. package/README.md +27 -230
  3. package/package.json +5 -4
package/README.ko.md ADDED
@@ -0,0 +1,55 @@
1
+ # @nest-batch/typeorm
2
+
3
+ `@nest-batch/core`용 TypeORM persistence adapter입니다.
4
+
5
+ English: [README.md](./README.md)
6
+
7
+ ## 설치
8
+
9
+ ```bash
10
+ pnpm add @nest-batch/core @nest-batch/typeorm typeorm
11
+ ```
12
+
13
+ Nest 애플리케이션에서 `@nestjs/typeorm`을 사용한다면 기존 `TypeOrmModule.forRoot`
14
+ 구성을 그대로 소유하면 됩니다.
15
+
16
+ ## Public Import
17
+
18
+ ```ts
19
+ import {
20
+ BATCH_META_ENTITIES,
21
+ TypeOrmAdapter,
22
+ TypeOrmJobRepository,
23
+ TypeOrmTransactionManager,
24
+ batchMetaEntities,
25
+ } from '@nest-batch/typeorm';
26
+ ```
27
+
28
+ ## Wiring
29
+
30
+ host-owned TypeORM data source에 batch metadata entity를 등록합니다.
31
+
32
+ ```ts
33
+ import { TypeOrmModule } from '@nestjs/typeorm';
34
+ import { InProcessAdapter, NestBatchModule } from '@nest-batch/core';
35
+ import { BATCH_META_ENTITIES, TypeOrmAdapter } from '@nest-batch/typeorm';
36
+
37
+ @Module({
38
+ imports: [
39
+ TypeOrmModule.forRoot({
40
+ type: 'postgres',
41
+ entities: [ProductEntity, ...BATCH_META_ENTITIES],
42
+ url: process.env.DATABASE_URL,
43
+ }),
44
+ NestBatchModule.forRoot({
45
+ adapters: {
46
+ persistence: TypeOrmAdapter.forRoot(),
47
+ transport: InProcessAdapter.forRoot(),
48
+ },
49
+ }),
50
+ ],
51
+ })
52
+ export class AppModule {}
53
+ ```
54
+
55
+ metadata entity를 추가한 뒤 application repository에서 migration을 생성하세요.
package/README.md CHANGED
@@ -1,259 +1,56 @@
1
- # `@nest-batch/typeorm`
1
+ # @nest-batch/typeorm
2
2
 
3
- The TypeORM 1.0.0 adapter for [`@nest-batch/core`](../core). It owns
4
- the same five active batch meta-tables that
5
- `@nest-batch/mikro-orm` ships, expressed as TypeORM 1.0 entities plus
6
- an exported entity tuple. It exposes `TypeOrmJobRepository` and
7
- `TypeOrmTransactionManager` and runs the shared core contract suite
8
- against a real TypeORM `DataSource`.
3
+ TypeORM persistence adapter for `@nest-batch/core`.
9
4
 
10
- The package is a **sibling**, not a replacement. The dependency
11
- direction is strict and one-way:
12
-
13
- ```
14
- @nest-batch/typeorm ──▶ @nest-batch/core
15
-
16
- └──────▶ typeorm (peer, ^1.0.0)
17
- ```
18
-
19
- `@nest-batch/core` does not know this package exists. The boundary is
20
- enforced by a core test that fails the build if any `typeorm` import
21
- shows up in core.
22
-
23
- ---
24
-
25
- ## TypeORM 1.0.0-only policy
26
-
27
- This adapter targets **TypeORM 1.0.0 only**. The peer range is
28
- `typeorm: ^1.0.0` and intentionally excludes `0.3.x`.
29
-
30
- Why 1.0.0 and not 0.3? Two reasons:
31
-
32
- 1. The `Connection` → `DataSource` rename. TypeORM 1.0.0 finished the
33
- rename that 0.3 started; the API now exposes `DataSource`,
34
- `DataSourceOptions`, and `DataSource.transaction()` instead of
35
- `Connection`, `ConnectionOptions`, and `Connection.transaction()`.
36
- Maintaining 0.3 support would mean running the full codebase
37
- through `Connection → DataSource` shims, which is a waste of
38
- effort when 0.3 is on a separate support track.
39
- 2. The entity surface. A few decorators and metadata helpers moved
40
- between 0.3 and 1.0. Supporting both means conditional entity
41
- definitions, which is a smell.
42
-
43
- The peer range is `^1.0.0`, so any 1.x release works. The boundary
44
- test in core and a dedicated peer-range test in this package
45
- together ensure 0.3 does not silently sneak back in.
46
-
47
- If you're on TypeORM 0.3, stay on the previous
48
- `@nest-batch/nest-batch` package (pre-rename) or upgrade TypeORM
49
- first. There's no compatibility shim in this release.
50
-
51
- ---
5
+ Korean: [README.ko.md](./README.ko.md)
52
6
 
53
7
  ## Install
54
8
 
55
9
  ```bash
56
- pnpm add @nest-batch/typeorm
10
+ pnpm add @nest-batch/core @nest-batch/typeorm typeorm
57
11
  ```
58
12
 
59
- Peer dependencies the host must already provide:
60
-
61
- | Package | Range |
62
- | ------------------ | ------------- |
63
- | `@nest-batch/core` | `workspace:*` |
64
- | `typeorm` | `^1.0.0` |
65
-
66
- `typeorm` is a hard peer (declared in `peerDependencies` with
67
- `optional: false`). The `package.json` also lists it as a
68
- `devDependency` so the package's own test suite can resolve it
69
- without the host.
70
-
71
- ---
72
-
73
- ## Schema ownership
74
-
75
- This package owns the same five active batch meta tables as
76
- `@nest-batch/mikro-orm`:
13
+ If your Nest application uses `@nestjs/typeorm`, keep using your normal
14
+ `TypeOrmModule.forRoot` configuration.
77
15
 
78
- | Table | Purpose |
79
- | ------------------------------ | ---------------------------------------------------------------------------------- |
80
- | `batch_job_instance` | One row per logical job (unique on `job_name`+`job_key`). |
81
- | `batch_job_execution` | One row per job run. Holds status, start/end, exit code/message. |
82
- | `batch_step_execution` | One row per step run. Holds step status, exit code/message, last-chunk checkpoint. |
83
- | `batch_job_execution_context` | JSON checkpoint + execution context (job-scoped). |
84
- | `batch_step_execution_context` | JSON checkpoint + execution context (step-scoped). |
16
+ ## Public Imports
85
17
 
86
- This package does not publish a runnable migration class. Apps that
87
- already have a TypeORM migration directory should spread
88
- `batchMetaEntities()` into their `entities` list, run TypeORM's
89
- `migration:generate` / `migration:create` flow in the app
90
- repository, and own the resulting migration file there.
91
-
92
- > **Note:** The five batch meta entities are also exported as a
93
- > single tuple under `batchMetaEntities` from the package root.
94
- > Because the adapter no longer bootstraps the `DataSource` (the
95
- > host owns the `TypeOrmModule.forRoot()` call), spreading
96
- > `batchMetaEntities` into your own `entities` array is the only
97
- > way the meta tables are registered with TypeORM's metadata
98
- > system. Forgetting the spread means `Repository<Entity>` lookups
99
- > for the meta tables fail silently and the repository throws at
100
- > first call.
101
-
102
- > The entities declare portable logical column types because the
103
- > same contract is exercised against fast SQLite tests and real
104
- > PostgreSQL/MySQL driver shells. Host-owned migrations may map
105
- > those logical columns to dialect-specific types such as
106
- > `timestamptz` or `datetime(6)`.
107
-
108
- ---
18
+ ```ts
19
+ import {
20
+ BATCH_META_ENTITIES,
21
+ TypeOrmAdapter,
22
+ TypeOrmJobRepository,
23
+ TypeOrmTransactionManager,
24
+ batchMetaEntities,
25
+ } from '@nest-batch/typeorm';
26
+ ```
109
27
 
110
28
  ## Wiring
111
29
 
112
- Wire the adapter with two imports in `AppModule.imports`: a host-
113
- owned `TypeOrmModule.forRoot()` call (which builds the
114
- `DataSource` and registers the meta entities) and a
115
- `TypeOrmAdapter.forRoot()` carrier passed to
116
- `NestBatchModule.forRoot({ adapters: { persistence, ... } })`.
117
-
118
- ### Bring-your-own `DataSource` (recommended)
119
-
120
- If your app already uses `@nestjs/typeorm` (the typical case for a
121
- Nest app with user-domain entities), call
122
- `TypeOrmModule.forRoot()` yourself, spread `batchMetaEntities()`
123
- into its `entities` array, and pass the adapter's no-arg
124
- `TypeOrmAdapter.forRoot()` to `NestBatchModule.forRoot()` under
125
- `adapters.persistence`:
30
+ Register the batch metadata entities in your host-owned TypeORM data source.
126
31
 
127
32
  ```ts
128
- import { Module } from '@nestjs/common';
129
33
  import { TypeOrmModule } from '@nestjs/typeorm';
130
- import { NestBatchModule } from '@nest-batch/core';
131
- import { batchMetaEntities, TypeOrmAdapter } from '@nest-batch/typeorm';
132
- import { ProductEntity } from './entities/product.entity';
34
+ import { InProcessAdapter, NestBatchModule } from '@nest-batch/core';
35
+ import { BATCH_META_ENTITIES, TypeOrmAdapter } from '@nest-batch/typeorm';
133
36
 
134
37
  @Module({
135
38
  imports: [
136
39
  TypeOrmModule.forRoot({
137
40
  type: 'postgres',
138
- host: '127.0.0.1',
139
- port: 5434,
140
- username: 'demo',
141
- password: 'demo',
142
- database: 'nest_batch_demo',
143
- entities: [ProductEntity, ...batchMetaEntities()],
144
- migrations: [
145
- /* your app-owned migrations */
146
- ],
147
- migrationsRun: true,
41
+ entities: [ProductEntity, ...BATCH_META_ENTITIES],
42
+ url: process.env.DATABASE_URL,
148
43
  }),
149
44
  NestBatchModule.forRoot({
150
- adapters: { persistence: TypeOrmAdapter.forRoot() },
45
+ adapters: {
46
+ persistence: TypeOrmAdapter.forRoot(),
47
+ transport: InProcessAdapter.forRoot(),
48
+ },
151
49
  }),
152
50
  ],
153
51
  })
154
52
  export class AppModule {}
155
53
  ```
156
54
 
157
- `TypeOrmAdapter.forRoot()` takes no arguments on purpose. The host
158
- already owns the `TypeOrmModule.forRoot()` call; the adapter only
159
- declares its own provider and export surface. The
160
- `JOB_REPOSITORY_TOKEN` and `TRANSACTION_MANAGER_TOKEN` bindings are
161
- registered globally by the adapter, so you do **not** list
162
- `TypeOrmJobRepository` / `TypeOrmTransactionManager` in the
163
- `providers` array — they're already wired.
164
-
165
- > **Warning:** The adapter does **not** call `TypeOrmModule.forRoot()`
166
- > and does **not** create a `DataSource`. If you forget the
167
- > `TypeOrmModule.forRoot()` import, the app boots cleanly and the
168
- > batch module compiles, but the repository throws at first call
169
- > because `Repository<Entity>` resolution has nothing to bind to.
170
- > The two pieces are decoupled by design — the adapter is a
171
- > binding-only carrier, and the connection is the host's.
172
-
173
- > **Note:** `@nestjs/typeorm` defaults to `isGlobal: true`, which
174
- > is what the adapter assumes. Setting `isGlobal: false` breaks
175
- > `EntityManager` injection inside the adapter's own module: the
176
- > `DataSource` is registered on the host's `TypeOrmModule.forRoot()`
177
- > but the adapter module is `global: true`, so the `EntityManager`
178
- > token it needs is not exported across the boundary. Leave it at
179
- > the default unless you've wired an alternative.
180
-
181
- `forRootAsync` is the right call when the connection comes from a
182
- config service or a secret manager. Pass the standard `useFactory`
183
- plus `inject` list to `TypeOrmModule.forRootAsync()` and keep
184
- `TypeOrmAdapter.forRoot()` unchanged — the adapter doesn't care
185
- how the `DataSource` is built.
186
-
187
- ### DataSource, not Connection
188
-
189
- TypeORM 1.0.0 calls it `DataSource`. The old `Connection` type is
190
- gone, and so is `getConnection()` / `getRepository()` on the
191
- connection. Every example in this README uses `DataSource`. If
192
- you're migrating from a 0.3 codebase, the rename touches every
193
- test file, every import, and every import path — there is no
194
- `@typeorm/0.3-compat` shim.
195
-
196
- The `TypeOrmTransactionManager` accepts a `DataSource` and uses
197
- `dataSource.transaction()` to start a real DB transaction. The
198
- callback receives a transactional `EntityManager`; use that one,
199
- not a globally-injected one, so all reads and writes are part of
200
- the same transaction.
201
-
202
- ---
203
-
204
- ## DB-first semantics
205
-
206
- The repository is the durable source of truth for execution state.
207
- Same model as the MikroORM adapter, same invariants:
208
-
209
- 1. **The DB is canonical.** A BullMQ job is a correlation stamp, not
210
- a state row. The `JobExecution` row carries the actual
211
- `status`, `startTime`, `endTime`, `exitCode`, and `exitMessage`.
212
- 2. **Atomic launches are enforced by the row lock.** The
213
- `createExecutionAtomic` flow uses a transactional
214
- `SELECT ... FOR UPDATE SKIP LOCKED` (on PostgreSQL) to serialize
215
- concurrent launches. Two callers racing to launch the same
216
- `jobName + jobKey` get one winner; the loser sees a thrown
217
- `JobExecutionAlreadyRunningError`.
218
- 3. **Restart and checkpoint go through the DB.** `findLatestStepExecution`
219
- returns the most recent `StepExecution` for `(jobExecutionId, stepName)`
220
- regardless of status, so the executor can load the
221
- last-committed chunk index from
222
- `batch_step_execution_context` and resume from there.
223
-
224
- The contract suite is the same one `@nest-batch/mikro-orm` runs. If
225
- you change the repository or transaction manager, run the suite to
226
- confirm you haven't broken the contract.
227
-
228
- ---
229
-
230
- ## What is NOT in this package
231
-
232
- - A TypeORM 0.3 adapter. Use 1.0.0 or stay on the previous package.
233
- - A Drizzle adapter. Drizzle is explicitly excluded from this
234
- release. See `MIGRATION.md`.
235
- - A MikroORM adapter. Use `@nest-batch/mikro-orm` if you want
236
- MikroORM 6; the two packages expose the same six-table schema.
237
- - A transport. Use `@nest-batch/bullmq` to wire BullMQ as the
238
- execution strategy; the transport layer reads the same
239
- `JobExecution` rows.
240
- - An admin UI, metrics, tracing, webhook, or job visualization
241
- surface. Out of scope for the whole `@nest-batch/*` family.
242
-
243
- ---
244
-
245
- ## Scripts
246
-
247
- ```bash
248
- pnpm --filter @nest-batch/typeorm build # SWC transpile + tsc declarations
249
- pnpm --filter @nest-batch/typeorm test # vitest run (uses better-sqlite3 by default)
250
- pnpm --filter @nest-batch/typeorm test:watch # vitest watch
251
- pnpm --filter @nest-batch/typeorm typecheck # tsc --noEmit
252
- ```
253
-
254
- The contract suite runs against an in-memory SQLite database by
255
- default. The test driver is `better-sqlite3` because it gives
256
- sub-millisecond setup and teardown, and the contract tests are
257
- database-agnostic enough to not need a full PostgreSQL harness.
258
- For an end-to-end Postgres run, point the suite at your own
259
- `DataSource` via the documented test harness hook.
55
+ Generate migrations in the application repository after adding the metadata
56
+ entities.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nest-batch/typeorm",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "TypeORM 1.0.0 adapter SLOT for @nest-batch/core — JobRepository and TransactionManager interface shape, paired with @nest-batch/postgresql (Postgres driver) or @nest-batch/mysql (MySQL driver).",
5
5
  "license": "MIT",
6
6
  "author": "easdkr",
@@ -25,7 +25,8 @@
25
25
  "files": [
26
26
  "dist/src",
27
27
  "src",
28
- "README.md"
28
+ "README.md",
29
+ "README.ko.md"
29
30
  ],
30
31
  "publishConfig": {
31
32
  "access": "public"
@@ -33,7 +34,7 @@
33
34
  "peerDependencies": {
34
35
  "@nestjs/common": "^10 || ^11",
35
36
  "typeorm": "^1.0.0",
36
- "@nest-batch/core": "^0.2.2"
37
+ "@nest-batch/core": "^0.2.4"
37
38
  },
38
39
  "peerDependenciesMeta": {
39
40
  "typeorm": {
@@ -58,7 +59,7 @@
58
59
  "typescript": "^5.5.0",
59
60
  "unplugin-swc": "^1.5.0",
60
61
  "vitest": "^2.0.0",
61
- "@nest-batch/core": "0.2.2"
62
+ "@nest-batch/core": "0.2.4"
62
63
  },
63
64
  "scripts": {
64
65
  "build": "swc src -d dist --config-file ../../.swcrc && tsc --emitDeclarationOnly -p tsconfig.build.json",