@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.
Files changed (2) hide show
  1. package/README.md +189 -127
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @ttoss/postgresdb
2
2
 
3
- This package uses [Sequelize](https://sequelize.org/) to provide a simple framework for working with PostgreSQL databases.
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
- ### ESM only
12
+ **ESM only**: Add `"type": "module"` to your `package.json`.
13
13
 
14
- This package is [ESM only](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c). Make sure to use it in an ESM environment.
14
+ ## Quick Start
15
15
 
16
- ```json
17
- {
18
- "type": "module"
19
- }
20
- ```
16
+ ### Database Setup
21
17
 
22
- ## Usage
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
- If you want to use [Docker Compose](https://docs.docker.com/compose/), you can create a `docker-compose.yml` file with the following content:
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
- ### Create a model
45
+ ### Define Models
56
46
 
57
- Create a folder called `models` and add a new file called `User.ts` with the following content:
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
- Export the model in the `models/index.ts` file:
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
- ### Create a new instance of the database
72
+ ### Initialize Database
81
73
 
82
- Create a new file called `src/db.ts` with the following content:
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
- _Note: the script [`sync`](#sync-the-database-schema) will use the `db` object to sync the database schema with the models._
92
-
93
- ### Environment variables
94
-
95
- You can set the database connection parameters in two ways:
83
+ ### Configuration
96
84
 
97
- 1. Defining them in the `src/db.ts` file using the `initialize` function.
85
+ **Option 1 - Direct configuration:**
98
86
 
99
- ```typescript
100
- export const db = initialize({
101
- database: '', // database name
102
- username: '', // database username
103
- password: '', // database password
104
- host: '', // database host
105
- port: 5432, // database port. Default: 5432
106
- models,
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
- `@ttoss/postgresdb` will use them automatically if they are defined.
98
+ **Option 2 - Environment variables (`.env`):**
119
99
 
120
- Here is an example of a `.env` file:
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
- ```env
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 the database schema
110
+ ### Sync Schema
131
111
 
132
- To [sync](https://sequelize.org/docs/v6/core-concepts/model-basics/#model-synchronization) the database schema with the models, use the [`sync` command](https://ttoss.dev/docs/modules/packages/postgresdb-cli/):
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
- By now, you should have a working database with a `User` table.
118
+ This imports `db` from `src/db.ts` and syncs the schema.
139
119
 
140
- This command works by importing the `db` object from the `src/db.ts` file and calling the `sync` method on it.
120
+ ### CRUD Operations
141
121
 
142
- ### CRUD operations
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
- All models are available in the `db` object.
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
- ### Using in a monorepo
156
+ **In consuming packages:**
158
157
 
159
- If you want to use in a monorepo by sharing the models between packages, you need to create some configurations to make it work.
158
+ Add dependencies to `package.json`:
160
159
 
161
- #### On the `postgresdb` package
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
- 1. Create your `postgresdb` package following the steps above.
190
+ ## Testing
164
191
 
165
- 1. Exports your main file in the `package.json` file:
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
- ```json
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
- 1. Create a new file called `src/index.ts` with the following content to exports the `models` you've created:
196
+ ### Setup
175
197
 
176
- ```typescript
177
- export * as models from './models';
178
- ```
198
+ **1. Install dependencies:**
179
199
 
180
- _We recommend to not export the `db` object in this file because you may want to use different configurations in different packages._
200
+ ```bash
201
+ pnpm add -D @testcontainers/postgresql jest @types/jest
202
+ ```
181
203
 
182
- #### On the other packages
204
+ **2. Configure `tsconfig.json`:**
205
+
206
+ ```json
207
+ {
208
+ "compilerOptions": {
209
+ "experimentalDecorators": true,
210
+ "emitDecoratorMetadata": true
211
+ }
212
+ }
213
+ ```
183
214
 
184
- 1. Install `@ttoss/postgresdb` package:
215
+ These options are required for decorator support. Without them, TypeScript won't properly compile decorator metadata.
185
216
 
186
- ```bash
187
- pnpm add @ttoss/postgresdb
188
- ```
217
+ **3. Add build script to `package.json`:**
189
218
 
190
- 1. Add your `postgresdb` package as a dependency. In the case you're using PNPM, you can use the [workspace protocol](https://pnpm.io/workspaces#workspace-protocol-workspace):
219
+ ```json
220
+ {
221
+ "scripts": {
222
+ "build": "tsup",
223
+ "pretest": "pnpm run build",
224
+ "test": "jest"
225
+ }
226
+ }
227
+ ```
191
228
 
192
- ```json
193
- {
194
- "dependencies": {
195
- "@yourproject/postgresdb": "workspace:^"
196
- }
197
- }
198
- ```
229
+ The `pretest` script ensures models are built before tests run.
199
230
 
200
- 1. Include the `postgresdb` package in the `include` field of the `tsconfig.json` file:
231
+ ### Test Example
201
232
 
202
- ```json
203
- {
204
- "include": ["src", "../postgresdb/src"]
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
- _This way, you can import the models using the `@yourproject/postgresdb` package._
267
+ afterAll(async () => {
268
+ await sequelize.close();
269
+ await postgresContainer.stop();
270
+ });
209
271
 
210
- 1. Create a new file called `src/db.ts` with the following content:
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
- ```typescript
213
- import { initialize } from '@ttoss/postgresdb';
214
- import { models } from '@yourproject/postgresdb';
277
+ const foundUser = await models.User.findByPk(user.id);
278
+ expect(foundUser).toMatchObject(userData);
279
+ });
280
+ });
281
+ ```
215
282
 
216
- export const db = initialize({
217
- models,
218
- // other configurations
219
- });
220
- ```
283
+ ### Key Points
221
284
 
222
- 1. Use the `db` object to interact with the database.
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
- ## API
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
- ### `initialize(options: InitializeOptions): db`
293
+ ## API Reference
227
294
 
228
- Initialize the database connection and load the models.
295
+ ### `initialize(options)`
229
296
 
230
- #### Options
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) are available, expect `models`.
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`: An object with all models to be loaded. The keys are the model names, and the values are the model classes. This way, you can access the models using the `db` object.
301
+ - `models` (required): Object mapping model names to model classes
235
302
 
236
- ### Sequelize decorators
303
+ ### Decorators
237
304
 
238
- This package exports all decorators from [sequelize-typescript](https://www.npmjs.com/package/sequelize-typescript), i.e., `@Table`, `@Column`, `@ForeignKey`, etc.
305
+ All [sequelize-typescript](https://www.npmjs.com/package/sequelize-typescript) decorators are exported: `@Table`, `@Column`, `@ForeignKey`, etc.
239
306
 
240
- ## Types
307
+ ### Types
241
308
 
242
- ### `ModelColumns<T>`
309
+ #### `ModelColumns<T>`
243
310
 
244
- A type that represents the columns of a model.
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.22",
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
- "import": "./dist/esm/index.js",
19
- "types": "./dist/index.d.ts"
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.10"
34
+ "@ttoss/config": "^1.35.11"
35
35
  },
36
36
  "keywords": [
37
37
  "database",