@trafficgroup/knex-rel 0.0.13 → 0.0.15
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/CLAUDE.md +59 -0
- package/dist/dao/user/user.dao.d.ts +1 -0
- package/dist/dao/user/user.dao.js +6 -0
- package/dist/dao/user/user.dao.js.map +1 -1
- package/dist/interfaces/video/video.interfaces.d.ts +3 -1
- package/migrations/20250722210109_migration.ts +60 -0
- package/migrations/20250722211019_migration.ts +15 -0
- package/package.json +2 -2
- package/src/dao/user/user.dao.ts +6 -0
- package/src/interfaces/video/video.interfaces.ts +3 -1
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
This is `@trafficgroup/knex-rel` - a TypeScript-based Knex.js module for database operations with PostgreSQL. It provides a standardized data access layer with DAOs (Data Access Objects) and interfaces for various entities.
|
|
8
|
+
|
|
9
|
+
## Development Commands
|
|
10
|
+
|
|
11
|
+
### Building and Formatting
|
|
12
|
+
- `npm run build` - Compile TypeScript to JavaScript in dist/
|
|
13
|
+
- `npm run format` - Format code with Prettier
|
|
14
|
+
- `npm run clean` - Clean dist/, format, and rebuild
|
|
15
|
+
- `npm test` - Run Jest tests
|
|
16
|
+
|
|
17
|
+
### Database Operations
|
|
18
|
+
- `npm run migrate:create` - Create a new TypeScript migration file
|
|
19
|
+
- `npm run migrate:deploy` - Run all pending migrations
|
|
20
|
+
- `npm run seed:create` - Create a new TypeScript seed file
|
|
21
|
+
- `npm run seed:run` - Execute all seed files
|
|
22
|
+
|
|
23
|
+
### Publishing
|
|
24
|
+
- `npm run npm:publish` - Clean, build, and publish to npm
|
|
25
|
+
|
|
26
|
+
## Architecture
|
|
27
|
+
|
|
28
|
+
### Core Components
|
|
29
|
+
|
|
30
|
+
**KnexManager** (`src/KnexConnection.ts`): Singleton connection manager
|
|
31
|
+
- `connect(config?, connections?)` - Establish database connection
|
|
32
|
+
- `getConnection()` - Get active connection instance
|
|
33
|
+
- `disconnect()` - Close connection and cleanup
|
|
34
|
+
|
|
35
|
+
**DAO Pattern**: All data access follows the `IBaseDAO<T>` interface with standard CRUD operations:
|
|
36
|
+
- `create(item)`, `getById(id)`, `getByUuid(uuid)`, `getAll(page, limit)`, `update(id, item)`, `delete(id)`
|
|
37
|
+
- Returns `IDataPaginator<T>` for paginated results
|
|
38
|
+
|
|
39
|
+
### Entity Structure
|
|
40
|
+
|
|
41
|
+
Each entity has:
|
|
42
|
+
- Interface in `src/interfaces/[entity]/[entity].interfaces.ts`
|
|
43
|
+
- DAO implementation in `src/dao/[entity]/[entity].dao.ts`
|
|
44
|
+
|
|
45
|
+
Current entities: User, Study, Folder, Video
|
|
46
|
+
|
|
47
|
+
### Database Configuration
|
|
48
|
+
|
|
49
|
+
Environment variables (for development):
|
|
50
|
+
- `SQL_HOST`, `SQL_USER`, `SQL_PASSWORD`, `SQL_DB_NAME`, `SQL_PORT`
|
|
51
|
+
|
|
52
|
+
Environment variables (for staging/production):
|
|
53
|
+
- `PG_HOST`, `PG_USER`, `PG_PASSWORD`, `PG_DB`, `PG_PORT`
|
|
54
|
+
|
|
55
|
+
Knex configuration supports development, staging, and production environments in `knexfile.ts`.
|
|
56
|
+
|
|
57
|
+
### Migrations
|
|
58
|
+
|
|
59
|
+
Located in `migrations/` directory. Use TypeScript format with timestamp prefixes. Database uses `knex_migrations` table for tracking.
|
|
@@ -5,6 +5,7 @@ export declare class UserDAO implements IBaseDAO<IUser> {
|
|
|
5
5
|
create(item: IUser): Promise<IUser>;
|
|
6
6
|
getById(id: number): Promise<IUser | null>;
|
|
7
7
|
getByUuid(uuid: string): Promise<IUser | null>;
|
|
8
|
+
getByEmail(email: string): Promise<IUser | null>;
|
|
8
9
|
update(id: number, item: Partial<IUser>): Promise<IUser | null>;
|
|
9
10
|
delete(id: number): Promise<boolean>;
|
|
10
11
|
getAll(page: number, limit: number): Promise<IDataPaginator<IUser>>;
|
|
@@ -36,6 +36,12 @@ class UserDAO {
|
|
|
36
36
|
return user || null;
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
|
+
getByEmail(email) {
|
|
40
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
41
|
+
const user = yield this._knex("users").where({ email }).first();
|
|
42
|
+
return user || null;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
39
45
|
update(id, item) {
|
|
40
46
|
return __awaiter(this, void 0, void 0, function* () {
|
|
41
47
|
const [updatedUser] = yield this._knex("users").where({ id }).update(item).returning("*");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.dao.js","sourceRoot":"","sources":["../../../src/dao/user/user.dao.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAGA,0EAA+C;AAE/C,MAAa,OAAO;IAApB;QACY,UAAK,GAAyB,wBAAW,CAAC,aAAa,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"user.dao.js","sourceRoot":"","sources":["../../../src/dao/user/user.dao.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAGA,0EAA+C;AAE/C,MAAa,OAAO;IAApB;QACY,UAAK,GAAyB,wBAAW,CAAC,aAAa,EAAE,CAAC;IAkDtE,CAAC;IAhDS,MAAM,CAAC,IAAW;;YACpB,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC5E,OAAO,WAAW,CAAC;QACvB,CAAC;KAAA;IAEK,OAAO,CAAC,EAAU;;YACpB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;YAC7D,OAAO,IAAI,IAAI,IAAI,CAAC;QACxB,CAAC;KAAA;IAEK,SAAS,CAAC,IAAY;;YACxB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;YAC/D,OAAO,IAAI,IAAI,IAAI,CAAC;QACxB,CAAC;KAAA;IAGK,UAAU,CAAC,KAAa;;YAC1B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;YAChE,OAAO,IAAI,IAAI,IAAI,CAAC;QACxB,CAAC;KAAA;IAEK,MAAM,CAAC,EAAU,EAAE,IAAoB;;YACzC,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;YAC1F,OAAO,WAAW,IAAI,IAAI,CAAC;QAC/B,CAAC;KAAA;IAEK,MAAM,CAAC,EAAU;;YACnB,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;YAC7D,OAAO,MAAM,GAAG,CAAC,CAAC;QACtB,CAAC;KAAA;IAEK,MAAM,CAAC,IAAY,EAAE,KAAa;;YACpC,MAAM,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;YAElC,MAAM,CAAC,WAAW,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;YACpE,MAAM,UAAU,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC;YACtC,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAEpE,OAAO;gBACH,OAAO,EAAE,IAAI;gBACb,IAAI,EAAE,KAAK;gBACX,IAAI;gBACJ,KAAK;gBACL,KAAK,EAAE,KAAK,CAAC,MAAM;gBACnB,UAAU;gBACV,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC;aAC5C,CAAC;QACN,CAAC;KAAA;CACJ;AAnDD,0BAmDC"}
|
|
@@ -8,7 +8,9 @@ export interface IVideo {
|
|
|
8
8
|
videoRate: number;
|
|
9
9
|
videoType: 'TMC' | 'ATR' | 'JUNCTION' | 'ROUNDABOUT' | 'PATHWAY';
|
|
10
10
|
metadata: Record<string, any>;
|
|
11
|
-
status: 'QUEUED' | 'PROCESSING' | 'COMPLETED' | 'FAILED';
|
|
11
|
+
status: 'QUEUED' | 'PROCESSING' | 'COMPLETED' | 'FAILED' | 'PENDING';
|
|
12
|
+
progress: number;
|
|
13
|
+
remainingTime: string;
|
|
12
14
|
results: Record<string, any>;
|
|
13
15
|
created_at: string;
|
|
14
16
|
updated_at: string;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export async function up(knex: Knex): Promise<void> {
|
|
5
|
+
// 1. Crear el tipo ENUM nativo
|
|
6
|
+
await knex.raw(`CREATE TYPE "video_status" AS ENUM ('QUEUED', 'PROCESSING', 'COMPLETED', 'FAILED', 'PENDING');`);
|
|
7
|
+
|
|
8
|
+
// 2. Normalizar los valores existentes
|
|
9
|
+
await knex.raw(`
|
|
10
|
+
UPDATE "video"
|
|
11
|
+
SET "status" = 'QUEUED'
|
|
12
|
+
WHERE "status" = 'QUEUE';
|
|
13
|
+
`);
|
|
14
|
+
|
|
15
|
+
// 3. Crear columna temporal del tipo ENUM
|
|
16
|
+
await knex.raw(`
|
|
17
|
+
ALTER TABLE "video"
|
|
18
|
+
ADD COLUMN "status_tmp" "video_status" DEFAULT 'PENDING';
|
|
19
|
+
`);
|
|
20
|
+
|
|
21
|
+
// 4. Copiar los valores de la columna original a la temporal
|
|
22
|
+
await knex.raw(`
|
|
23
|
+
UPDATE "video"
|
|
24
|
+
SET "status_tmp" = "status"::text::"video_status";
|
|
25
|
+
`);
|
|
26
|
+
|
|
27
|
+
// 5. Eliminar la columna original
|
|
28
|
+
await knex.raw(`
|
|
29
|
+
ALTER TABLE "video"
|
|
30
|
+
DROP COLUMN "status";
|
|
31
|
+
`);
|
|
32
|
+
|
|
33
|
+
// 6. Renombrar la columna temporal
|
|
34
|
+
await knex.raw(`
|
|
35
|
+
ALTER TABLE "video"
|
|
36
|
+
RENAME COLUMN "status_tmp" TO "status";
|
|
37
|
+
`);
|
|
38
|
+
|
|
39
|
+
// 7. Restaurar el default a 'PENDING'
|
|
40
|
+
await knex.raw(`
|
|
41
|
+
ALTER TABLE "video"
|
|
42
|
+
ALTER COLUMN "status" SET DEFAULT 'PENDING';
|
|
43
|
+
`);
|
|
44
|
+
|
|
45
|
+
// 8. Agregar columnas nuevas
|
|
46
|
+
await knex.schema.alterTable("video", (table) => {
|
|
47
|
+
table.integer("progress").notNullable().defaultTo(0);
|
|
48
|
+
table.string("remainingTime", 255).notNullable().defaultTo("0");
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function down(knex: Knex): Promise<void> {
|
|
53
|
+
await knex.schema.alterTable("video", (table) => {
|
|
54
|
+
table.dropColumn("progress");
|
|
55
|
+
table.dropColumn("remainingTime");
|
|
56
|
+
table.specificType("status", "varchar(255)").notNullable().defaultTo("QUEUED").alter();
|
|
57
|
+
});
|
|
58
|
+
await knex.raw('DROP TYPE IF EXISTS "video_status";');
|
|
59
|
+
}
|
|
60
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Knex } from "knex";
|
|
2
|
+
|
|
3
|
+
export async function up(knex: Knex): Promise<void> {
|
|
4
|
+
await knex.raw(`
|
|
5
|
+
ALTER TABLE "video"
|
|
6
|
+
ALTER COLUMN "status" SET DEFAULT 'PENDING';
|
|
7
|
+
`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function down(knex: Knex): Promise<void> {
|
|
11
|
+
await knex.raw(`
|
|
12
|
+
ALTER TABLE "video"
|
|
13
|
+
ALTER COLUMN "status" SET DEFAULT 'QUEUED';
|
|
14
|
+
`);
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trafficgroup/knex-rel",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.15",
|
|
4
4
|
"description": "Knex Module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@eslint/js": "^9.23.0",
|
|
29
29
|
"@types/dotenv": "^6.1.1",
|
|
30
|
-
"@types/lodash": "^4.17.
|
|
30
|
+
"@types/lodash": "^4.17.20",
|
|
31
31
|
"@types/node": "^22.13.13",
|
|
32
32
|
"eslint": "^9.23.0",
|
|
33
33
|
"globals": "^16.0.0",
|
package/src/dao/user/user.dao.ts
CHANGED
|
@@ -21,6 +21,12 @@ export class UserDAO implements IBaseDAO<IUser> {
|
|
|
21
21
|
return user || null;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
+
|
|
25
|
+
async getByEmail(email: string): Promise<IUser | null> {
|
|
26
|
+
const user = await this._knex("users").where({ email }).first();
|
|
27
|
+
return user || null;
|
|
28
|
+
}
|
|
29
|
+
|
|
24
30
|
async update(id: number, item: Partial<IUser>): Promise<IUser | null> {
|
|
25
31
|
const [updatedUser] = await this._knex("users").where({ id }).update(item).returning("*");
|
|
26
32
|
return updatedUser || null;
|
|
@@ -9,7 +9,9 @@ export interface IVideo {
|
|
|
9
9
|
videoRate: number;
|
|
10
10
|
videoType: 'TMC' | 'ATR' | 'JUNCTION' | 'ROUNDABOUT' | 'PATHWAY';
|
|
11
11
|
metadata: Record<string, any>;
|
|
12
|
-
status: 'QUEUED' | 'PROCESSING' | 'COMPLETED' | 'FAILED';
|
|
12
|
+
status: 'QUEUED' | 'PROCESSING' | 'COMPLETED' | 'FAILED' | 'PENDING';
|
|
13
|
+
progress: number;
|
|
14
|
+
remainingTime: string;
|
|
13
15
|
results: Record<string, any>;
|
|
14
16
|
created_at: string;
|
|
15
17
|
updated_at: string;
|