@ttoss/postgresdb 0.2.22 → 0.2.24
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 +189 -127
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @ttoss/postgresdb
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A lightweight [Sequelize](https://sequelize.org/) wrapper for PostgreSQL databases with TypeScript support.
|
|
4
4
|
|
|
5
5
|
## Installation
|
|
6
6
|
|
|
@@ -9,27 +9,19 @@ pnpm add @ttoss/postgresdb
|
|
|
9
9
|
pnpm add -D @ttoss/postgresdb-cli
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**ESM only**: Add `"type": "module"` to your `package.json`.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
## Quick Start
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
"type": "module"
|
|
19
|
-
}
|
|
20
|
-
```
|
|
16
|
+
### Database Setup
|
|
21
17
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
### Setup the database
|
|
25
|
-
|
|
26
|
-
If you already have a database, you can skip this step. If you don't, you can use the following Docker command to create a new PostgreSQL database on port 5432 using Docker:
|
|
18
|
+
Use Docker to create a PostgreSQL instance:
|
|
27
19
|
|
|
28
20
|
```bash
|
|
29
21
|
docker run --name postgres-test -e POSTGRES_PASSWORD=mysecretpassword -d -p 5432:5432 postgres
|
|
30
22
|
```
|
|
31
23
|
|
|
32
|
-
|
|
24
|
+
Or with Docker Compose (`docker-compose.yml`):
|
|
33
25
|
|
|
34
26
|
```yaml
|
|
35
27
|
services:
|
|
@@ -46,15 +38,13 @@ volumes:
|
|
|
46
38
|
db-data:
|
|
47
39
|
```
|
|
48
40
|
|
|
49
|
-
And run the following command:
|
|
50
|
-
|
|
51
41
|
```bash
|
|
52
42
|
docker compose up -d
|
|
53
43
|
```
|
|
54
44
|
|
|
55
|
-
###
|
|
45
|
+
### Define Models
|
|
56
46
|
|
|
57
|
-
Create
|
|
47
|
+
Create `models/User.ts`:
|
|
58
48
|
|
|
59
49
|
```typescript
|
|
60
50
|
import { Table, Column, Model } from '@ttoss/postgresdb';
|
|
@@ -67,19 +57,21 @@ export class User extends Model<User> {
|
|
|
67
57
|
@Column
|
|
68
58
|
declare email: string;
|
|
69
59
|
}
|
|
70
|
-
|
|
71
|
-
_This packages exports all decorators from [sequelize-typescript](https://github.com/sequelize/sequelize-typescript), so you can use them to define your models._
|
|
72
60
|
```
|
|
73
61
|
|
|
74
|
-
|
|
62
|
+
**Important:** You must use the `declare` keyword on class properties to ensure TypeScript doesn't emit them as actual fields. Without `declare`, public class fields would shadow Sequelize's getters and setters, blocking access to the model's data. See [Sequelize documentation on public class fields](https://sequelize.org/docs/v6/core-concepts/model-basics/#caveat-with-public-class-fields) for details.
|
|
63
|
+
|
|
64
|
+
_All [sequelize-typescript](https://github.com/sequelize/sequelize-typescript) decorators are available._
|
|
65
|
+
|
|
66
|
+
Export in `models/index.ts`:
|
|
75
67
|
|
|
76
68
|
```typescript
|
|
77
69
|
export { User } from './User';
|
|
78
70
|
```
|
|
79
71
|
|
|
80
|
-
###
|
|
72
|
+
### Initialize Database
|
|
81
73
|
|
|
82
|
-
Create
|
|
74
|
+
Create `src/db.ts`:
|
|
83
75
|
|
|
84
76
|
```typescript
|
|
85
77
|
import { initialize } from '@ttoss/postgresdb';
|
|
@@ -88,60 +80,46 @@ import * as models from './models';
|
|
|
88
80
|
export const db = await initialize({ models });
|
|
89
81
|
```
|
|
90
82
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
### Environment variables
|
|
94
|
-
|
|
95
|
-
You can set the database connection parameters in two ways:
|
|
83
|
+
### Configuration
|
|
96
84
|
|
|
97
|
-
1
|
|
85
|
+
**Option 1 - Direct configuration:**
|
|
98
86
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
2. Using environment variables:
|
|
111
|
-
|
|
112
|
-
- `DB_NAME`: database name
|
|
113
|
-
- `DB_USERNAME`: database username
|
|
114
|
-
- `DB_PASSWORD`: database password
|
|
115
|
-
- `DB_HOST`: database host
|
|
116
|
-
- `DB_PORT`: database port. Default: 5432
|
|
87
|
+
```typescript
|
|
88
|
+
export const db = initialize({
|
|
89
|
+
database: 'mydb',
|
|
90
|
+
username: 'user',
|
|
91
|
+
password: 'pass',
|
|
92
|
+
host: 'localhost',
|
|
93
|
+
port: 5432,
|
|
94
|
+
models,
|
|
95
|
+
});
|
|
96
|
+
```
|
|
117
97
|
|
|
118
|
-
|
|
98
|
+
**Option 2 - Environment variables (`.env`):**
|
|
119
99
|
|
|
120
|
-
|
|
100
|
+
```env
|
|
101
|
+
DB_NAME=postgres
|
|
102
|
+
DB_USERNAME=postgres
|
|
103
|
+
DB_PASSWORD=mysecretpassword
|
|
104
|
+
DB_HOST=localhost
|
|
105
|
+
DB_PORT=5432
|
|
106
|
+
```
|
|
121
107
|
|
|
122
|
-
|
|
123
|
-
DB_NAME=postgres
|
|
124
|
-
DB_USERNAME=postgres
|
|
125
|
-
DB_PASSWORD=mysecretpassword
|
|
126
|
-
DB_HOST=localhost
|
|
127
|
-
DB_PORT=5432
|
|
128
|
-
```
|
|
108
|
+
Environment variables are automatically used if defined.
|
|
129
109
|
|
|
130
|
-
### Sync
|
|
110
|
+
### Sync Schema
|
|
131
111
|
|
|
132
|
-
|
|
112
|
+
[Synchronize](https://sequelize.org/docs/v6/core-concepts/model-basics/#model-synchronization) database schema with models:
|
|
133
113
|
|
|
134
114
|
```bash
|
|
135
115
|
pnpm dlx @ttoss/postgresdb-cli sync
|
|
136
116
|
```
|
|
137
117
|
|
|
138
|
-
|
|
118
|
+
This imports `db` from `src/db.ts` and syncs the schema.
|
|
139
119
|
|
|
140
|
-
|
|
120
|
+
### CRUD Operations
|
|
141
121
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
You can now use the `db` object to interact with the database. Check the [Sequelize documentation](https://sequelize.org/master/manual/model-querying-basics.html) for more information.
|
|
122
|
+
All models are accessible via the `db` object. See [Sequelize documentation](https://sequelize.org/master/manual/model-querying-basics.html) for complete query API.
|
|
145
123
|
|
|
146
124
|
```typescript
|
|
147
125
|
import { db } from './db';
|
|
@@ -152,96 +130,185 @@ const user = await db.User.create({
|
|
|
152
130
|
});
|
|
153
131
|
```
|
|
154
132
|
|
|
155
|
-
|
|
133
|
+
## Monorepo Usage
|
|
134
|
+
|
|
135
|
+
Share models across packages with this setup:
|
|
136
|
+
|
|
137
|
+
**In the database package (`@yourproject/postgresdb`):**
|
|
138
|
+
|
|
139
|
+
`package.json`:
|
|
140
|
+
|
|
141
|
+
```json
|
|
142
|
+
{
|
|
143
|
+
"type": "module",
|
|
144
|
+
"exports": "./src/index.ts"
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
`src/index.ts`:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
export * as models from './models';
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
_Don't export `db` here - each package may need different configurations._
|
|
156
155
|
|
|
157
|
-
|
|
156
|
+
**In consuming packages:**
|
|
158
157
|
|
|
159
|
-
|
|
158
|
+
Add dependencies to `package.json`:
|
|
160
159
|
|
|
161
|
-
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"dependencies": {
|
|
163
|
+
"@ttoss/postgresdb": "^x.x.x",
|
|
164
|
+
"@yourproject/postgresdb": "workspace:^"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Update `tsconfig.json`:
|
|
170
|
+
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"compilerOptions": {
|
|
174
|
+
"experimentalDecorators": true,
|
|
175
|
+
"emitDecoratorMetadata": true
|
|
176
|
+
},
|
|
177
|
+
"include": ["src", "../postgresdb/src"]
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Create `src/db.ts`:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
import { initialize } from '@ttoss/postgresdb';
|
|
185
|
+
import { models } from '@yourproject/postgresdb';
|
|
186
|
+
|
|
187
|
+
export const db = initialize({ models });
|
|
188
|
+
```
|
|
162
189
|
|
|
163
|
-
|
|
190
|
+
## Testing
|
|
164
191
|
|
|
165
|
-
|
|
192
|
+
Testing models with decorators requires special configuration because Jest's Babel transformer doesn't properly transpile TypeScript decorators. The solution is to build your models before running tests.
|
|
166
193
|
|
|
167
|
-
|
|
168
|
-
{
|
|
169
|
-
"type": "module",
|
|
170
|
-
"exports": "./src/index.ts"
|
|
171
|
-
}
|
|
172
|
-
```
|
|
194
|
+
**Why test your models?** Beyond validating functionality, tests serve as a critical safety check for schema changes. They ensure that running `sync --alter` won't accidentally remove columns or relationships from your database. If a model property is missing or incorrectly defined, tests will fail before you can damage production data.
|
|
173
195
|
|
|
174
|
-
|
|
196
|
+
### Setup
|
|
175
197
|
|
|
176
|
-
|
|
177
|
-
export * as models from './models';
|
|
178
|
-
```
|
|
198
|
+
**1. Install dependencies:**
|
|
179
199
|
|
|
180
|
-
|
|
200
|
+
```bash
|
|
201
|
+
pnpm add -D @testcontainers/postgresql jest @types/jest
|
|
202
|
+
```
|
|
181
203
|
|
|
182
|
-
|
|
204
|
+
**2. Configure `tsconfig.json`:**
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
{
|
|
208
|
+
"compilerOptions": {
|
|
209
|
+
"experimentalDecorators": true,
|
|
210
|
+
"emitDecoratorMetadata": true
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
183
214
|
|
|
184
|
-
|
|
215
|
+
These options are required for decorator support. Without them, TypeScript won't properly compile decorator metadata.
|
|
185
216
|
|
|
186
|
-
|
|
187
|
-
pnpm add @ttoss/postgresdb
|
|
188
|
-
```
|
|
217
|
+
**3. Add build script to `package.json`:**
|
|
189
218
|
|
|
190
|
-
|
|
219
|
+
```json
|
|
220
|
+
{
|
|
221
|
+
"scripts": {
|
|
222
|
+
"build": "tsup",
|
|
223
|
+
"pretest": "pnpm run build",
|
|
224
|
+
"test": "jest"
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
191
228
|
|
|
192
|
-
|
|
193
|
-
{
|
|
194
|
-
"dependencies": {
|
|
195
|
-
"@yourproject/postgresdb": "workspace:^"
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
```
|
|
229
|
+
The `pretest` script ensures models are built before tests run.
|
|
199
230
|
|
|
200
|
-
|
|
231
|
+
### Test Example
|
|
201
232
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
233
|
+
```typescript
|
|
234
|
+
import {
|
|
235
|
+
PostgreSqlContainer,
|
|
236
|
+
StartedPostgreSqlContainer,
|
|
237
|
+
} from '@testcontainers/postgresql';
|
|
238
|
+
import { initialize, Sequelize } from '@ttoss/postgresdb';
|
|
239
|
+
import { models } from 'dist/index'; // Import from built output
|
|
240
|
+
|
|
241
|
+
let sequelize: Sequelize;
|
|
242
|
+
let postgresContainer: StartedPostgreSqlContainer;
|
|
243
|
+
|
|
244
|
+
jest.setTimeout(60000);
|
|
245
|
+
|
|
246
|
+
beforeAll(async () => {
|
|
247
|
+
// Start PostgreSQL container
|
|
248
|
+
postgresContainer = await new PostgreSqlContainer('postgres:17').start();
|
|
249
|
+
|
|
250
|
+
// Initialize database with container credentials
|
|
251
|
+
const db = await initialize({
|
|
252
|
+
models,
|
|
253
|
+
logging: false,
|
|
254
|
+
username: postgresContainer.getUsername(),
|
|
255
|
+
password: postgresContainer.getPassword(),
|
|
256
|
+
database: postgresContainer.getDatabase(),
|
|
257
|
+
host: postgresContainer.getHost(),
|
|
258
|
+
port: postgresContainer.getPort(),
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
sequelize = db.sequelize;
|
|
262
|
+
|
|
263
|
+
// Sync database schema
|
|
264
|
+
await sequelize.sync();
|
|
265
|
+
});
|
|
207
266
|
|
|
208
|
-
|
|
267
|
+
afterAll(async () => {
|
|
268
|
+
await sequelize.close();
|
|
269
|
+
await postgresContainer.stop();
|
|
270
|
+
});
|
|
209
271
|
|
|
210
|
-
|
|
272
|
+
describe('User model', () => {
|
|
273
|
+
test('should create and retrieve user', async () => {
|
|
274
|
+
const userData = { email: 'test@example.com' };
|
|
275
|
+
const user = await models.User.create(userData);
|
|
211
276
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
277
|
+
const foundUser = await models.User.findByPk(user.id);
|
|
278
|
+
expect(foundUser).toMatchObject(userData);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
```
|
|
215
282
|
|
|
216
|
-
|
|
217
|
-
models,
|
|
218
|
-
// other configurations
|
|
219
|
-
});
|
|
220
|
-
```
|
|
283
|
+
### Key Points
|
|
221
284
|
|
|
222
|
-
|
|
285
|
+
- **Import from `dist/`**: Tests must import models from the compiled output (`dist/index`), not source files, because decorators aren't transpiled by Jest's Babel transformer. See [this Stack Overflow answer](https://stackoverflow.com/a/53920890/8786986) for details.
|
|
286
|
+
- **Testcontainers**: Use [`@testcontainers/postgresql`](https://www.npmjs.com/package/@testcontainers/postgresql) to spin up isolated PostgreSQL instances for each test run.
|
|
287
|
+
- **Timeout**: Set a longer timeout with `jest.setTimeout(60000)` as container startup can take time.
|
|
288
|
+
- **Sync schema**: Call `sequelize.sync()` after initialization to create tables based on your models.
|
|
289
|
+
- **Schema validation**: Tests verify that all model properties are correctly defined. This prevents `sync --alter` from accidentally removing database columns due to missing or misconfigured model properties.
|
|
223
290
|
|
|
224
|
-
|
|
291
|
+
For a complete working example with full test configuration, see the [terezinha-farm/postgresdb](https://github.com/ttoss/ttoss/tree/main/terezinha-farm/postgresdb) example in this repository.
|
|
225
292
|
|
|
226
|
-
|
|
293
|
+
## API Reference
|
|
227
294
|
|
|
228
|
-
|
|
295
|
+
### `initialize(options)`
|
|
229
296
|
|
|
230
|
-
|
|
297
|
+
Initializes database connection and loads models.
|
|
231
298
|
|
|
232
|
-
All [Sequelize options](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-constructor-constructor)
|
|
299
|
+
**Options:** All [Sequelize options](https://sequelize.org/api/v6/class/src/sequelize.js~sequelize#instance-constructor-constructor) except `dialect` (always `postgres`), plus:
|
|
233
300
|
|
|
234
|
-
- `models
|
|
301
|
+
- `models` (required): Object mapping model names to model classes
|
|
235
302
|
|
|
236
|
-
###
|
|
303
|
+
### Decorators
|
|
237
304
|
|
|
238
|
-
|
|
305
|
+
All [sequelize-typescript](https://www.npmjs.com/package/sequelize-typescript) decorators are exported: `@Table`, `@Column`, `@ForeignKey`, etc.
|
|
239
306
|
|
|
240
|
-
|
|
307
|
+
### Types
|
|
241
308
|
|
|
242
|
-
|
|
309
|
+
#### `ModelColumns<T>`
|
|
243
310
|
|
|
244
|
-
|
|
311
|
+
Extracts column types from a model:
|
|
245
312
|
|
|
246
313
|
```typescript
|
|
247
314
|
import { Column, Model, type ModelColumns, Table } from '@ttoss/postgresdb';
|
|
@@ -255,11 +322,6 @@ class User extends Model<User> {
|
|
|
255
322
|
declare email: string;
|
|
256
323
|
}
|
|
257
324
|
|
|
258
|
-
|
|
259
|
-
* UserColumns = {
|
|
260
|
-
* name?: string;
|
|
261
|
-
* email: string;
|
|
262
|
-
* }
|
|
263
|
-
*/
|
|
325
|
+
// Inferred type: { name?: string; email: string; }
|
|
264
326
|
type UserColumns = ModelColumns<User>;
|
|
265
327
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ttoss/postgresdb",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.24",
|
|
4
4
|
"description": "A library to handle PostgreSQL database connections and queries",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ttoss",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"type": "module",
|
|
16
16
|
"exports": {
|
|
17
17
|
".": {
|
|
18
|
-
"
|
|
19
|
-
"
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"default": "./dist/esm/index.js"
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
"files": [
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"jest": "^30.2.0",
|
|
33
33
|
"tsup": "^8.5.1",
|
|
34
|
-
"@ttoss/config": "^1.35.
|
|
34
|
+
"@ttoss/config": "^1.35.11"
|
|
35
35
|
},
|
|
36
36
|
"keywords": [
|
|
37
37
|
"database",
|