@ttoss/postgresdb 0.2.27 → 0.4.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.md CHANGED
@@ -50,7 +50,7 @@ Create `models/User.ts`:
50
50
  import { Table, Column, Model } from '@ttoss/postgresdb';
51
51
 
52
52
  @Table
53
- export class User extends Model<User> {
53
+ export class User extends Model {
54
54
  @Column
55
55
  declare name: string;
56
56
 
@@ -130,6 +130,66 @@ const user = await db.User.create({
130
130
  });
131
131
  ```
132
132
 
133
+ ## Vector Support (pgvector)
134
+
135
+ This package includes built-in support for [pgvector](https://github.com/pgvector/pgvector), enabling vector similarity search for AI/ML applications like semantic search, recommendations, and RAG systems.
136
+
137
+ ### Setup
138
+
139
+ Enable pgvector by setting `createVectorExtension: true` when initializing:
140
+
141
+ ```typescript
142
+ import { initialize } from '@ttoss/postgresdb';
143
+ import * as models from './models';
144
+
145
+ export const db = await initialize({
146
+ models,
147
+ createVectorExtension: true, // Automatically creates the pgvector extension
148
+ });
149
+ ```
150
+
151
+ This automatically executes `CREATE EXTENSION IF NOT EXISTS vector` on your database.
152
+
153
+ ### Using VECTOR Type
154
+
155
+ Define vector columns using `DataType.VECTOR(dimensions)`:
156
+
157
+ ```typescript
158
+ import { Table, Column, Model, DataType } from '@ttoss/postgresdb';
159
+
160
+ @Table
161
+ class Document extends Model {
162
+ @Column
163
+ declare content: string;
164
+
165
+ @Column({
166
+ type: DataType.VECTOR(1536), // 1536-dimensional vector (e.g., OpenAI embeddings)
167
+ allowNull: true,
168
+ })
169
+ declare embedding: number[];
170
+ }
171
+ ```
172
+
173
+ ### Vector Operations
174
+
175
+ ```typescript
176
+ import { db } from './db';
177
+
178
+ // Create document with embedding
179
+ const doc = await db.Document.create({
180
+ content: 'Machine learning tutorial',
181
+ embedding: [0.1, 0.2, 0.3, ...], // 1536-dimensional array
182
+ });
183
+
184
+ // Find similar documents using cosine distance
185
+ const similar = await db.Document.findAll({
186
+ order: sequelize.literal(`embedding <=> '[0.1, 0.2, 0.3, ...]'`),
187
+ limit: 5,
188
+ });
189
+ ```
190
+
191
+ For advanced vector operations and indexing, see the [pgvector documentation](https://github.com/pgvector/pgvector#readme).
192
+
133
193
  ## Monorepo Usage
134
194
 
135
195
  Share models across packages with this setup:
@@ -193,6 +253,12 @@ Testing models with decorators requires special configuration because Jest's Bab
193
253
 
194
254
  **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.
195
255
 
256
+ :::warning Import from compiled output
257
+
258
+ 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.
259
+
260
+ :::
261
+
196
262
  ### Setup
197
263
 
198
264
  **1. Install dependencies:**
@@ -282,7 +348,6 @@ describe('User model', () => {
282
348
 
283
349
  ### Key Points
284
350
 
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
351
  - **Testcontainers**: Use [`@testcontainers/postgresql`](https://www.npmjs.com/package/@testcontainers/postgresql) to spin up isolated PostgreSQL instances for each test run.
287
352
  - **Timeout**: Set a longer timeout with `jest.setTimeout(60000)` as container startup can take time.
288
353
  - **Sync schema**: Call `sequelize.sync()` after initialization to create tables based on your models.
@@ -304,6 +369,97 @@ Initializes database connection and loads models.
304
369
 
305
370
  All [sequelize-typescript](https://www.npmjs.com/package/sequelize-typescript) decorators are exported: `@Table`, `@Column`, `@ForeignKey`, etc.
306
371
 
372
+ #### Hooks
373
+
374
+ Lifecycle hooks allow you to execute code at specific points in the model lifecycle. All hook decorators from sequelize-typescript are available:
375
+
376
+ **Instance Hooks:**
377
+
378
+ - `@BeforeValidate`, `@AfterValidate`, `@ValidationFailed`
379
+ - `@BeforeCreate`, `@AfterCreate`
380
+ - `@BeforeUpdate`, `@AfterUpdate`
381
+ - `@BeforeDestroy`, `@AfterDestroy`
382
+ - `@BeforeSave`, `@AfterSave` (v4 only)
383
+ - `@BeforeUpsert`, `@AfterUpsert` (v4 only)
384
+ - `@BeforeRestore`, `@AfterRestore`
385
+
386
+ **Bulk Hooks:**
387
+
388
+ - `@BeforeBulkCreate`, `@AfterBulkCreate`
389
+ - `@BeforeBulkUpdate`, `@AfterBulkUpdate`
390
+ - `@BeforeBulkDestroy`, `@AfterBulkDestroy`
391
+ - `@BeforeBulkRestore`, `@AfterBulkRestore`
392
+ - `@BeforeBulkSync`, `@AfterBulkSync`
393
+
394
+ **Query Hooks:**
395
+
396
+ - `@BeforeFind`, `@AfterFind`
397
+ - `@BeforeFindAfterExpandIncludeAll`, `@BeforeFindAfterOptions`
398
+ - `@BeforeCount`
399
+
400
+ **Connection Hooks:**
401
+
402
+ - `@BeforeConnect`, `@AfterConnect`
403
+ - `@BeforeDefine`, `@AfterDefine`
404
+ - `@BeforeInit`, `@AfterInit`
405
+
406
+ **Example:**
407
+
408
+ ```typescript
409
+ import {
410
+ Table,
411
+ Column,
412
+ Model,
413
+ BeforeCreate,
414
+ BeforeUpdate,
415
+ } from '@ttoss/postgresdb';
416
+
417
+ @Table
418
+ class Product extends Model {
419
+ @Column
420
+ declare name: string;
421
+
422
+ @Column
423
+ declare slug: string;
424
+
425
+ @BeforeCreate
426
+ static generateSlug(instance: Product) {
427
+ if (instance.name && !instance.slug) {
428
+ instance.slug = instance.name.toLowerCase().replace(/\s+/g, '-');
429
+ }
430
+ }
431
+
432
+ @BeforeUpdate
433
+ static updateSlug(instance: Product) {
434
+ if (instance.changed('name') && instance.name) {
435
+ instance.slug = instance.name.toLowerCase().replace(/\s+/g, '-');
436
+ }
437
+ }
438
+ }
439
+ ```
440
+
441
+ See the [sequelize-typescript hooks documentation](https://github.com/sequelize/sequelize-typescript#hooks) for more details.
442
+
443
+ ### DataType
444
+
445
+ All standard Sequelize data types are available through `DataType`, including:
446
+
447
+ - **`DataType.VECTOR(dimensions)`**: PostgreSQL vector type for storing embeddings (requires [pgvector](https://github.com/pgvector/pgvector) extension). Use for AI/ML applications like semantic search and recommendations.
448
+
449
+ Example:
450
+
451
+ ```typescript
452
+ import { Column, DataType } from '@ttoss/postgresdb';
453
+
454
+ @Column({
455
+ type: DataType.VECTOR(768), // 768-dimensional vector
456
+ allowNull: true,
457
+ })
458
+ declare embedding: number[];
459
+ ```
460
+
461
+ See [Sequelize DataTypes documentation](https://sequelize.org/docs/v6/core-concepts/model-basics/#data-types) for all available types.
462
+
307
463
  ### Types
308
464
 
309
465
  #### `ModelColumns<T>`
@@ -314,7 +470,7 @@ Extracts column types from a model:
314
470
  import { Column, Model, type ModelColumns, Table } from '@ttoss/postgresdb';
315
471
 
316
472
  @Table
317
- class User extends Model<User> {
473
+ class User extends Model {
318
474
  @Column
319
475
  declare name?: string;
320
476
 
package/dist/esm/index.js CHANGED
@@ -6,12 +6,17 @@ var __name = (target, value) => __defProp(target, "name", {
6
6
  });
7
7
 
8
8
  // src/sequelize-typescript.ts
9
- import { BelongsTo, BelongsToMany, Column, CreatedAt, DataType, DeletedAt, ForeignKey, HasMany, HasOne, Index, Model, PrimaryKey, Sequelize, Table, Unique, UpdatedAt } from "sequelize-typescript";
9
+ import pgvector from "pgvector/sequelize";
10
+ import { DataType as SequelizeDataType, Sequelize } from "sequelize-typescript";
11
+ import { AfterBulkCreate, AfterBulkDestroy, AfterBulkRestore, AfterBulkSync, AfterBulkUpdate, AfterConnect, AfterCreate, AfterDefine, AfterDestroy, AfterFind, AfterInit, AfterRestore, AfterSave, AfterUpdate, AfterUpsert, AfterValidate, BeforeBulkCreate, BeforeBulkDestroy, BeforeBulkRestore, BeforeBulkSync, BeforeBulkUpdate, BeforeConnect, BeforeCount, BeforeCreate, BeforeDefine, BeforeDestroy, BeforeFind, BeforeFindAfterExpandIncludeAll, BeforeFindAfterOptions, BeforeInit, BeforeRestore, BeforeSave, BeforeUpdate, BeforeUpsert, BeforeValidate, BelongsTo, BelongsToMany, Column, CreatedAt, DeletedAt, ForeignKey, HasMany, HasOne, Index, Model, PrimaryKey, Sequelize as Sequelize2, Table, Unique, UpdatedAt, ValidationFailed } from "sequelize-typescript";
12
+ pgvector.registerType(Sequelize);
13
+ var DataType = SequelizeDataType;
10
14
 
11
15
  // src/initialize.ts
12
16
  var sequelize;
13
17
  var initialize = /* @__PURE__ */__name(async ({
14
18
  models,
19
+ createVectorExtension = false,
15
20
  ...restOptions
16
21
  }) => {
17
22
  const username = process.env.DATABASE_USER,
@@ -20,7 +25,7 @@ var initialize = /* @__PURE__ */__name(async ({
20
25
  host = process.env.DATABASE_HOST,
21
26
  port = Number(process.env.DATABASE_PORT) || 5432;
22
27
  if (!sequelize) {
23
- sequelize = new Sequelize({
28
+ sequelize = new Sequelize2({
24
29
  logging: false,
25
30
  username,
26
31
  password,
@@ -43,6 +48,9 @@ var initialize = /* @__PURE__ */__name(async ({
43
48
  if (username && password && database && host && port) {
44
49
  await sequelize.authenticate();
45
50
  }
51
+ if (createVectorExtension) {
52
+ await sequelize.query("CREATE EXTENSION IF NOT EXISTS vector;");
53
+ }
46
54
  const close = sequelize.close;
47
55
  return {
48
56
  sequelize,
@@ -53,4 +61,4 @@ var initialize = /* @__PURE__ */__name(async ({
53
61
 
54
62
  // src/index.ts
55
63
  import { Op } from "sequelize";
56
- export { BelongsTo, BelongsToMany, Column, CreatedAt, DataType, DeletedAt, ForeignKey, HasMany, HasOne, Index, Model, Op, PrimaryKey, Sequelize, Table, Unique, UpdatedAt, initialize };
64
+ export { AfterBulkCreate, AfterBulkDestroy, AfterBulkRestore, AfterBulkSync, AfterBulkUpdate, AfterConnect, AfterCreate, AfterDefine, AfterDestroy, AfterFind, AfterInit, AfterRestore, AfterSave, AfterUpdate, AfterUpsert, AfterValidate, BeforeBulkCreate, BeforeBulkDestroy, BeforeBulkRestore, BeforeBulkSync, BeforeBulkUpdate, BeforeConnect, BeforeCount, BeforeCreate, BeforeDefine, BeforeDestroy, BeforeFind, BeforeFindAfterExpandIncludeAll, BeforeFindAfterOptions, BeforeInit, BeforeRestore, BeforeSave, BeforeUpdate, BeforeUpsert, BeforeValidate, BelongsTo, BelongsToMany, Column, CreatedAt, DataType, DeletedAt, ForeignKey, HasMany, HasOne, Index, Model, Op, PrimaryKey, Sequelize2 as Sequelize, Table, Unique, UpdatedAt, ValidationFailed, initialize };
package/dist/index.d.ts CHANGED
@@ -1,16 +1,30 @@
1
- import { ModelCtor, SequelizeOptions, Sequelize, Model } from 'sequelize-typescript';
2
- export { BelongsTo, BelongsToMany, Column, CreatedAt, DataType, DeletedAt, ForeignKey, HasMany, HasOne, Index, Model, ModelCtor, PrimaryKey, Sequelize, SequelizeOptions, Table, Unique, UpdatedAt } from 'sequelize-typescript';
1
+ import { DataType as DataType$1, ModelCtor, SequelizeOptions, Sequelize, Model } from 'sequelize-typescript';
2
+ export { AfterBulkCreate, AfterBulkDestroy, AfterBulkRestore, AfterBulkSync, AfterBulkUpdate, AfterConnect, AfterCreate, AfterDefine, AfterDestroy, AfterFind, AfterInit, AfterRestore, AfterSave, AfterUpdate, AfterUpsert, AfterValidate, BeforeBulkCreate, BeforeBulkDestroy, BeforeBulkRestore, BeforeBulkSync, BeforeBulkUpdate, BeforeConnect, BeforeCount, BeforeCreate, BeforeDefine, BeforeDestroy, BeforeFind, BeforeFindAfterExpandIncludeAll, BeforeFindAfterOptions, BeforeInit, BeforeRestore, BeforeSave, BeforeUpdate, BeforeUpsert, BeforeValidate, BelongsTo, BelongsToMany, Column, CreatedAt, DeletedAt, ForeignKey, HasMany, HasOne, Index, Model, ModelCtor, PrimaryKey, Sequelize, SequelizeOptions, Table, Unique, UpdatedAt, ValidationFailed } from 'sequelize-typescript';
3
+ import { DataType as DataType$2 } from 'sequelize';
3
4
  export { Op } from 'sequelize';
4
5
 
6
+ /**
7
+ * Extend DataType to include VECTOR type from pgvector
8
+ */
9
+ declare const DataType: typeof DataType$1 & {
10
+ VECTOR: (dimensions: number) => DataType$2;
11
+ };
12
+
5
13
  type Options<Models> = Omit<SequelizeOptions, 'models' | 'dialect'> & {
6
14
  models: Models;
15
+ /**
16
+ * If true, creates the pgvector extension in the database.
17
+ * This is required to use VECTOR data types.
18
+ * @default false
19
+ */
20
+ createVectorExtension?: boolean;
7
21
  };
8
22
  declare const initialize: <Models extends {
9
23
  [key: string]: ModelCtor;
10
- }>({ models, ...restOptions }: Options<Models>) => Promise<{
24
+ }>({ models, createVectorExtension, ...restOptions }: Options<Models>) => Promise<{
11
25
  sequelize: Sequelize;
12
26
  } & Models>;
13
27
 
14
28
  type ModelColumns<T> = Omit<T, keyof Model> & Pick<Model, 'id' | 'createdAt' | 'updatedAt'>;
15
29
 
16
- export { type ModelColumns, initialize };
30
+ export { DataType, type ModelColumns, initialize };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/postgresdb",
3
- "version": "0.2.27",
3
+ "version": "0.4.0",
4
4
  "description": "A library to handle PostgreSQL database connections and queries",
5
5
  "license": "MIT",
6
6
  "author": "ttoss",
@@ -25,10 +25,12 @@
25
25
  "sideEffects": false,
26
26
  "dependencies": {
27
27
  "pg": "^8.16.3",
28
+ "pgvector": "^0.2.1",
28
29
  "sequelize": "^6.37.7",
29
30
  "sequelize-typescript": "^2.1.6"
30
31
  },
31
32
  "devDependencies": {
33
+ "@testcontainers/postgresql": "^11.8.1",
32
34
  "jest": "^30.2.0",
33
35
  "tsup": "^8.5.1",
34
36
  "@ttoss/config": "^1.35.12"
@@ -44,6 +46,7 @@
44
46
  },
45
47
  "scripts": {
46
48
  "build": "tsup",
47
- "test": "echo jest"
49
+ "pretest": "tsup --config ./tests/tsup.pretest.config.ts",
50
+ "test": "jest --projects tests/unit"
48
51
  }
49
52
  }