@mini-yt/database 0.0.1
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/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/migrations/20260102181525264_initial_tables.d.ts +4 -0
- package/dist/migrations/20260102181525264_initial_tables.d.ts.map +1 -0
- package/dist/migrations/20260102181525264_initial_tables.js +72 -0
- package/dist/migrations/20260106161533054_refresh_token.d.ts +4 -0
- package/dist/migrations/20260106161533054_refresh_token.d.ts.map +1 -0
- package/dist/migrations/20260106161533054_refresh_token.js +34 -0
- package/dist/scripts/create-migrations.d.ts +2 -0
- package/dist/scripts/create-migrations.d.ts.map +1 -0
- package/dist/scripts/create-migrations.js +24 -0
- package/dist/scripts/migrate.d.ts +2 -0
- package/dist/scripts/migrate.d.ts.map +1 -0
- package/dist/scripts/migrate.js +12 -0
- package/dist/scripts/rollback.d.ts +2 -0
- package/dist/scripts/rollback.d.ts.map +1 -0
- package/dist/scripts/rollback.js +12 -0
- package/dist/scripts/seed.d.ts +2 -0
- package/dist/scripts/seed.d.ts.map +1 -0
- package/dist/scripts/seed.js +16 -0
- package/package.json +32 -0
- package/src/index.ts +43 -0
- package/src/migrations/20260102181525264_initial_tables.ts +79 -0
- package/src/migrations/20260106161533054_refresh_token.ts +36 -0
- package/src/scripts/create-migrations.ts +31 -0
- package/src/scripts/migrate.ts +13 -0
- package/src/scripts/rollback.ts +14 -0
- package/src/scripts/seed.ts +16 -0
- package/tsconfig.json +18 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Knex as IKnex } from "knex";
|
|
2
|
+
import { types } from "@mini-yt/shared";
|
|
3
|
+
export declare function createDb(dbConfig?: types.database.TDbConfig): IKnex;
|
|
4
|
+
export declare function getDb(): IKnex | null;
|
|
5
|
+
export declare function closeDb(): Promise<void>;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAa,EAAE,IAAI,IAAI,KAAK,EAAE,MAAM,MAAM,CAAC;AAC3C,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAGxC,wBAAgB,QAAQ,CACtB,QAAQ,GAAE,KAAK,CAAC,QAAQ,CAAC,SAExB,GACA,KAAK,CAmBP;AACD,wBAAgB,KAAK,IAAI,KAAK,GAAG,IAAI,CAGpC;AAED,wBAAsB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAS7C"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import knex from "knex";
|
|
2
|
+
let db;
|
|
3
|
+
export function createDb(dbConfig = {
|
|
4
|
+
DATABASE_URL: process.env.DATABASE_URL ?? "",
|
|
5
|
+
}) {
|
|
6
|
+
try {
|
|
7
|
+
if (db)
|
|
8
|
+
return db;
|
|
9
|
+
db = knex({
|
|
10
|
+
client: "pg",
|
|
11
|
+
connection: dbConfig.DATABASE_URL,
|
|
12
|
+
migrations: {
|
|
13
|
+
directory: __dirname + "/migrations",
|
|
14
|
+
},
|
|
15
|
+
seeds: {
|
|
16
|
+
directory: __dirname + "/seeds",
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
return db;
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.log("ERROR IN CREATING DB CLIENT", error);
|
|
23
|
+
throw new Error(`DATA_BASE init failed ${error}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function getDb() {
|
|
27
|
+
if (!db)
|
|
28
|
+
return null;
|
|
29
|
+
return db;
|
|
30
|
+
}
|
|
31
|
+
export async function closeDb() {
|
|
32
|
+
try {
|
|
33
|
+
if (db) {
|
|
34
|
+
await db.destroy();
|
|
35
|
+
db = null;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
throw new Error("Error closing the database connection");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260102181525264_initial_tables.d.ts","sourceRoot":"","sources":["../../src/migrations/20260102181525264_initial_tables.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AA+D5B,wBAAsB,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAOlD;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAMpD"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { CONSTANTS } from "@mini-yt/shared";
|
|
2
|
+
const { DEFAULTS, ENUMS, TABLES } = CONSTANTS.DATABASE;
|
|
3
|
+
const { TB_USER, TB_CHANNEL, TB_VIDEOS } = TABLES;
|
|
4
|
+
const { SCHEMA } = DEFAULTS;
|
|
5
|
+
async function createUserTable(knex) {
|
|
6
|
+
const tbUser = await knex.schema.withSchema(SCHEMA).hasTable(TB_USER);
|
|
7
|
+
if (!tbUser)
|
|
8
|
+
await knex.schema.withSchema(SCHEMA).createTable(TB_USER, (tbl) => {
|
|
9
|
+
tbl.uuid("id").primary().defaultTo(knex.raw(`uuidv7()`));
|
|
10
|
+
tbl.text("email").unique().notNullable();
|
|
11
|
+
tbl.string("password").notNullable();
|
|
12
|
+
tbl.timestamp("created_at").defaultTo(knex.fn.now());
|
|
13
|
+
tbl.timestamp("updated_at").defaultTo(knex.fn.now());
|
|
14
|
+
tbl.boolean("is_deleted").defaultTo(false);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
async function createChannelTable(knex) {
|
|
18
|
+
const tbChannel = await knex.schema.withSchema(SCHEMA).hasTable(TB_CHANNEL);
|
|
19
|
+
if (!tbChannel)
|
|
20
|
+
await knex.schema.withSchema(SCHEMA).createTable(TB_CHANNEL, (tbl) => {
|
|
21
|
+
tbl.uuid("id").primary().defaultTo(knex.raw(`uuidv7()`));
|
|
22
|
+
tbl
|
|
23
|
+
.uuid("owner")
|
|
24
|
+
.references("id")
|
|
25
|
+
.inTable(`${SCHEMA}.${TB_USER}`)
|
|
26
|
+
.notNullable();
|
|
27
|
+
tbl.text("name").notNullable();
|
|
28
|
+
tbl.text("handle").unique().notNullable();
|
|
29
|
+
tbl.timestamp("created_at").defaultTo(knex.fn.now());
|
|
30
|
+
tbl.timestamp("updated_at").defaultTo(knex.fn.now());
|
|
31
|
+
tbl.boolean("is_deleted").defaultTo(false);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
async function createVideosTable(knex) {
|
|
35
|
+
const tbVideos = await knex.schema.withSchema(SCHEMA).hasTable(TB_VIDEOS);
|
|
36
|
+
if (!tbVideos)
|
|
37
|
+
await knex.schema.withSchema(SCHEMA).createTable(TB_VIDEOS, (tbl) => {
|
|
38
|
+
tbl.uuid("id").primary().defaultTo(knex.raw(`uuidv7()`));
|
|
39
|
+
tbl
|
|
40
|
+
.uuid("channel")
|
|
41
|
+
.references("id")
|
|
42
|
+
.inTable(`${SCHEMA}.${TB_CHANNEL}`)
|
|
43
|
+
.notNullable();
|
|
44
|
+
tbl.text("title").notNullable();
|
|
45
|
+
tbl.text("description");
|
|
46
|
+
tbl.enu("visibility", ENUMS.VISIBILITY).defaultTo(DEFAULTS.VISIBILITY);
|
|
47
|
+
tbl.enu("status", ENUMS.STATUS).defaultTo(DEFAULTS.VIDEO_UPLOAD_STATUS);
|
|
48
|
+
tbl.text("raw_s3_key").notNullable();
|
|
49
|
+
tbl.text("processed_prefix");
|
|
50
|
+
tbl.bigint("duration");
|
|
51
|
+
tbl.timestamp("created_at").defaultTo(knex.fn.now());
|
|
52
|
+
tbl.timestamp("published_at");
|
|
53
|
+
tbl.timestamp("updated_at").defaultTo(knex.fn.now());
|
|
54
|
+
tbl.boolean("is_deleted").defaultTo(false);
|
|
55
|
+
tbl.index("channel");
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export async function up(knex) {
|
|
59
|
+
await knex.transaction(async (trx) => {
|
|
60
|
+
await trx.schema.createSchemaIfNotExists(SCHEMA);
|
|
61
|
+
await createUserTable(trx);
|
|
62
|
+
await createChannelTable(trx);
|
|
63
|
+
await createVideosTable(trx);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
export async function down(knex) {
|
|
67
|
+
await knex.transaction(async (trx) => {
|
|
68
|
+
await trx.schema.withSchema(SCHEMA).dropTableIfExists(TB_VIDEOS);
|
|
69
|
+
await trx.schema.withSchema(SCHEMA).dropTableIfExists(TB_CHANNEL);
|
|
70
|
+
await trx.schema.withSchema(SCHEMA).dropTableIfExists(TB_USER);
|
|
71
|
+
});
|
|
72
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"20260106161533054_refresh_token.d.ts","sourceRoot":"","sources":["../../src/migrations/20260106161533054_refresh_token.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAyB5B,wBAAsB,EAAE,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAIlD;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CONSTANTS } from "@mini-yt/shared";
|
|
2
|
+
const { DEFAULTS, ENUMS, TABLES } = CONSTANTS.DATABASE;
|
|
3
|
+
const { TB_REFRESH_TOKEN, TB_USER } = TABLES;
|
|
4
|
+
const { SCHEMA } = DEFAULTS;
|
|
5
|
+
const createRefreshTokenTable = async (knex) => {
|
|
6
|
+
const tblExists = await knex.schema
|
|
7
|
+
.withSchema(SCHEMA)
|
|
8
|
+
.hasTable(TB_REFRESH_TOKEN);
|
|
9
|
+
if (tblExists)
|
|
10
|
+
return;
|
|
11
|
+
await knex.schema.withSchema(SCHEMA).createTable(TB_REFRESH_TOKEN, (tbl) => {
|
|
12
|
+
tbl.uuid("id").primary().defaultTo(knex.raw("uuidv7()"));
|
|
13
|
+
tbl
|
|
14
|
+
.uuid("user")
|
|
15
|
+
.references("id")
|
|
16
|
+
.inTable(`${SCHEMA}.${TB_USER}`)
|
|
17
|
+
.notNullable()
|
|
18
|
+
.onDelete("CASCADE");
|
|
19
|
+
tbl.text("token_hash").notNullable();
|
|
20
|
+
tbl.timestamp("expires_at").notNullable();
|
|
21
|
+
tbl.timestamp("created_at").notNullable().defaultTo(knex.fn.now());
|
|
22
|
+
tbl.timestamp("updated_at").notNullable().defaultTo(knex.fn.now());
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
export async function up(knex) {
|
|
26
|
+
await knex.transaction(async (trx) => {
|
|
27
|
+
await createRefreshTokenTable(trx);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export async function down(knex) {
|
|
31
|
+
await knex.transaction(async (trx) => {
|
|
32
|
+
await trx.schema.withSchema(SCHEMA).dropTableIfExists(TB_REFRESH_TOKEN);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-migrations.d.ts","sourceRoot":"","sources":["../../src/scripts/create-migrations.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
const name = process.argv[2];
|
|
4
|
+
if (!name) {
|
|
5
|
+
console.error("MIGRATION FILE NAME IS REQUIRED!!");
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
const MIGRATIONS_DIR = path.resolve(__dirname, "../migrations");
|
|
9
|
+
if (!fs.existsSync(MIGRATIONS_DIR)) {
|
|
10
|
+
fs.mkdirSync(MIGRATIONS_DIR, { recursive: true });
|
|
11
|
+
}
|
|
12
|
+
const timestamp = new Date().toISOString().replace(/[-:T.Z]/g, "");
|
|
13
|
+
const filename = `${timestamp}_${name}.ts`;
|
|
14
|
+
const filePath = path.join(MIGRATIONS_DIR, filename);
|
|
15
|
+
const template = `import { Knex } from "knex";
|
|
16
|
+
|
|
17
|
+
export async function up(knex: Knex): Promise<void> {
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export async function down(knex: Knex): Promise<void> {
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
23
|
+
fs.writeFileSync(filePath, template);
|
|
24
|
+
console.log(`MIGRATION FILE ${name} CREATED AT ${MIGRATIONS_DIR}`);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../src/scripts/migrate.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createDb, getDb } from "..";
|
|
2
|
+
async function migrate() {
|
|
3
|
+
let db = getDb();
|
|
4
|
+
if (!db)
|
|
5
|
+
db = createDb();
|
|
6
|
+
const [batch, log] = await db.migrate.latest();
|
|
7
|
+
console.log({ batch, log });
|
|
8
|
+
process.exit(0);
|
|
9
|
+
}
|
|
10
|
+
migrate().catch((e) => {
|
|
11
|
+
console.error("Error in migrating the files", e.message);
|
|
12
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rollback.d.ts","sourceRoot":"","sources":["../../src/scripts/rollback.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getDb, createDb } from "..";
|
|
2
|
+
async function rollback() {
|
|
3
|
+
let db = getDb();
|
|
4
|
+
if (!db)
|
|
5
|
+
db = createDb();
|
|
6
|
+
const [batch, logs] = await db.migrate.rollback();
|
|
7
|
+
console.log({ batch, logs });
|
|
8
|
+
process.exit(0);
|
|
9
|
+
}
|
|
10
|
+
rollback().catch((e) => {
|
|
11
|
+
console.log("Error in rolling back", e.message);
|
|
12
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../../src/scripts/seed.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getDb, createDb } from "..";
|
|
2
|
+
async function seed() {
|
|
3
|
+
let db = getDb();
|
|
4
|
+
try {
|
|
5
|
+
if (!db)
|
|
6
|
+
db = createDb();
|
|
7
|
+
await db.seed.run();
|
|
8
|
+
process.exit(0);
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
throw error;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
seed().catch((e) => {
|
|
15
|
+
console.error(`Error in running seeds`, e.message);
|
|
16
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mini-yt/database",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"default": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"typecheck": "tsc --noEmit",
|
|
16
|
+
"create-migration": "tsx src/scripts/create-migrations.ts",
|
|
17
|
+
"migrate": "tsx src/scripts/migrate.ts",
|
|
18
|
+
"seed": "tsx src/scripts/seed.ts",
|
|
19
|
+
"rollback": "tsx src/scripts/rollback.ts"
|
|
20
|
+
},
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@mini-yt/shared": "workspace:*",
|
|
23
|
+
"dotenv": "^17.2.3",
|
|
24
|
+
"knex": "^3.1.0",
|
|
25
|
+
"pg": "^8.16.3"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^25.0.3",
|
|
29
|
+
"tsx": "^4.21.0",
|
|
30
|
+
"typescript": "^5.9.3"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import knex, { Knex as IKnex } from "knex";
|
|
2
|
+
import { types } from "@mini-yt/shared";
|
|
3
|
+
|
|
4
|
+
let db: IKnex | null;
|
|
5
|
+
export function createDb(
|
|
6
|
+
dbConfig: types.database.TDbConfig = {
|
|
7
|
+
DATABASE_URL: process.env.DATABASE_URL ?? "",
|
|
8
|
+
}
|
|
9
|
+
): IKnex {
|
|
10
|
+
try {
|
|
11
|
+
if (db) return db;
|
|
12
|
+
db = knex({
|
|
13
|
+
client: "pg",
|
|
14
|
+
connection: dbConfig.DATABASE_URL,
|
|
15
|
+
migrations: {
|
|
16
|
+
directory: __dirname + "/migrations",
|
|
17
|
+
},
|
|
18
|
+
seeds: {
|
|
19
|
+
directory: __dirname + "/seeds",
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
return db;
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.log("ERROR IN CREATING DB CLIENT", error);
|
|
26
|
+
throw new Error(`DATA_BASE init failed ${error}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function getDb(): IKnex | null {
|
|
30
|
+
if (!db) return null;
|
|
31
|
+
return db;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export async function closeDb(): Promise<void> {
|
|
35
|
+
try {
|
|
36
|
+
if (db) {
|
|
37
|
+
await db.destroy();
|
|
38
|
+
db = null;
|
|
39
|
+
}
|
|
40
|
+
} catch (error) {
|
|
41
|
+
throw new Error("Error closing the database connection");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Knex } from "knex";
|
|
2
|
+
import { CONSTANTS } from "@mini-yt/shared";
|
|
3
|
+
const { DEFAULTS, ENUMS, TABLES } = CONSTANTS.DATABASE;
|
|
4
|
+
const { TB_USER, TB_CHANNEL, TB_VIDEOS } = TABLES;
|
|
5
|
+
const { SCHEMA } = DEFAULTS;
|
|
6
|
+
|
|
7
|
+
async function createUserTable(knex: Knex): Promise<void> {
|
|
8
|
+
const tbUser = await knex.schema.withSchema(SCHEMA).hasTable(TB_USER);
|
|
9
|
+
if (!tbUser)
|
|
10
|
+
await knex.schema.withSchema(SCHEMA).createTable(TB_USER, (tbl) => {
|
|
11
|
+
tbl.uuid("id").primary().defaultTo(knex.raw(`uuidv7()`));
|
|
12
|
+
tbl.text("email").unique().notNullable();
|
|
13
|
+
tbl.string("password").notNullable();
|
|
14
|
+
tbl.timestamp("created_at").defaultTo(knex.fn.now());
|
|
15
|
+
tbl.timestamp("updated_at").defaultTo(knex.fn.now());
|
|
16
|
+
tbl.boolean("is_deleted").defaultTo(false);
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async function createChannelTable(knex: Knex): Promise<void> {
|
|
20
|
+
const tbChannel = await knex.schema.withSchema(SCHEMA).hasTable(TB_CHANNEL);
|
|
21
|
+
if (!tbChannel)
|
|
22
|
+
await knex.schema.withSchema(SCHEMA).createTable(TB_CHANNEL, (tbl) => {
|
|
23
|
+
tbl.uuid("id").primary().defaultTo(knex.raw(`uuidv7()`));
|
|
24
|
+
tbl
|
|
25
|
+
.uuid("owner")
|
|
26
|
+
.references("id")
|
|
27
|
+
.inTable(`${SCHEMA}.${TB_USER}`)
|
|
28
|
+
.notNullable();
|
|
29
|
+
tbl.text("name").notNullable();
|
|
30
|
+
tbl.text("handle").unique().notNullable();
|
|
31
|
+
tbl.timestamp("created_at").defaultTo(knex.fn.now());
|
|
32
|
+
tbl.timestamp("updated_at").defaultTo(knex.fn.now());
|
|
33
|
+
tbl.boolean("is_deleted").defaultTo(false);
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async function createVideosTable(knex: Knex): Promise<void> {
|
|
37
|
+
const tbVideos = await knex.schema.withSchema(SCHEMA).hasTable(TB_VIDEOS);
|
|
38
|
+
if (!tbVideos)
|
|
39
|
+
await knex.schema.withSchema(SCHEMA).createTable(TB_VIDEOS, (tbl) => {
|
|
40
|
+
tbl.uuid("id").primary().defaultTo(knex.raw(`uuidv7()`));
|
|
41
|
+
tbl
|
|
42
|
+
.uuid("channel")
|
|
43
|
+
.references("id")
|
|
44
|
+
.inTable(`${SCHEMA}.${TB_CHANNEL}`)
|
|
45
|
+
.notNullable();
|
|
46
|
+
tbl.text("title").notNullable();
|
|
47
|
+
tbl.text("description");
|
|
48
|
+
tbl.enu("visibility", ENUMS.VISIBILITY).defaultTo(DEFAULTS.VISIBILITY);
|
|
49
|
+
tbl.enu("status", ENUMS.STATUS).defaultTo(DEFAULTS.VIDEO_UPLOAD_STATUS);
|
|
50
|
+
|
|
51
|
+
tbl.text("raw_s3_key").notNullable();
|
|
52
|
+
tbl.text("processed_prefix");
|
|
53
|
+
tbl.bigint("duration");
|
|
54
|
+
|
|
55
|
+
tbl.timestamp("created_at").defaultTo(knex.fn.now());
|
|
56
|
+
tbl.timestamp("published_at");
|
|
57
|
+
tbl.timestamp("updated_at").defaultTo(knex.fn.now());
|
|
58
|
+
tbl.boolean("is_deleted").defaultTo(false);
|
|
59
|
+
|
|
60
|
+
tbl.index("channel");
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function up(knex: Knex): Promise<void> {
|
|
65
|
+
await knex.transaction(async (trx) => {
|
|
66
|
+
await trx.schema.createSchemaIfNotExists(SCHEMA);
|
|
67
|
+
await createUserTable(trx);
|
|
68
|
+
await createChannelTable(trx);
|
|
69
|
+
await createVideosTable(trx);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export async function down(knex: Knex): Promise<void> {
|
|
74
|
+
await knex.transaction(async (trx: Knex.Transaction) => {
|
|
75
|
+
await trx.schema.withSchema(SCHEMA).dropTableIfExists(TB_VIDEOS);
|
|
76
|
+
await trx.schema.withSchema(SCHEMA).dropTableIfExists(TB_CHANNEL);
|
|
77
|
+
await trx.schema.withSchema(SCHEMA).dropTableIfExists(TB_USER);
|
|
78
|
+
});
|
|
79
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Knex } from "knex";
|
|
2
|
+
import { CONSTANTS } from "@mini-yt/shared";
|
|
3
|
+
const { DEFAULTS, ENUMS, TABLES } = CONSTANTS.DATABASE;
|
|
4
|
+
const { TB_REFRESH_TOKEN, TB_USER } = TABLES;
|
|
5
|
+
const { SCHEMA } = DEFAULTS;
|
|
6
|
+
|
|
7
|
+
const createRefreshTokenTable = async (knex: Knex) => {
|
|
8
|
+
const tblExists = await knex.schema
|
|
9
|
+
.withSchema(SCHEMA)
|
|
10
|
+
.hasTable(TB_REFRESH_TOKEN);
|
|
11
|
+
if (tblExists) return;
|
|
12
|
+
await knex.schema.withSchema(SCHEMA).createTable(TB_REFRESH_TOKEN, (tbl) => {
|
|
13
|
+
tbl.uuid("id").primary().defaultTo(knex.raw("uuidv7()"));
|
|
14
|
+
tbl
|
|
15
|
+
.uuid("user")
|
|
16
|
+
.references("id")
|
|
17
|
+
.inTable(`${SCHEMA}.${TB_USER}`)
|
|
18
|
+
.notNullable()
|
|
19
|
+
.onDelete("CASCADE");
|
|
20
|
+
tbl.text("token_hash").notNullable();
|
|
21
|
+
tbl.timestamp("expires_at").notNullable();
|
|
22
|
+
tbl.timestamp("created_at").notNullable().defaultTo(knex.fn.now());
|
|
23
|
+
tbl.timestamp("updated_at").notNullable().defaultTo(knex.fn.now());
|
|
24
|
+
});
|
|
25
|
+
};
|
|
26
|
+
export async function up(knex: Knex): Promise<void> {
|
|
27
|
+
await knex.transaction(async (trx) => {
|
|
28
|
+
await createRefreshTokenTable(trx);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function down(knex: Knex): Promise<void> {
|
|
33
|
+
await knex.transaction(async (trx) => {
|
|
34
|
+
await trx.schema.withSchema(SCHEMA).dropTableIfExists(TB_REFRESH_TOKEN);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
|
|
4
|
+
const name = process.argv[2];
|
|
5
|
+
if (!name) {
|
|
6
|
+
console.error("MIGRATION FILE NAME IS REQUIRED!!");
|
|
7
|
+
process.exit(1);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const MIGRATIONS_DIR = path.resolve(__dirname, "../migrations");
|
|
11
|
+
|
|
12
|
+
if (!fs.existsSync(MIGRATIONS_DIR)) {
|
|
13
|
+
fs.mkdirSync(MIGRATIONS_DIR, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const timestamp = new Date().toISOString().replace(/[-:T.Z]/g, "");
|
|
17
|
+
const filename = `${timestamp}_${name}.ts`;
|
|
18
|
+
|
|
19
|
+
const filePath = path.join(MIGRATIONS_DIR, filename);
|
|
20
|
+
|
|
21
|
+
const template = `import { Knex } from "knex";
|
|
22
|
+
|
|
23
|
+
export async function up(knex: Knex): Promise<void> {
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function down(knex: Knex): Promise<void> {
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
fs.writeFileSync(filePath, template);
|
|
31
|
+
console.log(`MIGRATION FILE ${name} CREATED AT ${MIGRATIONS_DIR}`);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createDb, getDb } from "..";
|
|
2
|
+
|
|
3
|
+
async function migrate(): Promise<void> {
|
|
4
|
+
let db = getDb();
|
|
5
|
+
if (!db) db = createDb();
|
|
6
|
+
const [batch, log] = await db.migrate.latest();
|
|
7
|
+
console.log({ batch, log });
|
|
8
|
+
process.exit(0);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
migrate().catch((e: Error) => {
|
|
12
|
+
console.error("Error in migrating the files", e.message);
|
|
13
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getDb, createDb } from "..";
|
|
2
|
+
|
|
3
|
+
async function rollback() {
|
|
4
|
+
let db = getDb();
|
|
5
|
+
if (!db) db = createDb();
|
|
6
|
+
|
|
7
|
+
const [batch, logs] = await db.migrate.rollback();
|
|
8
|
+
console.log({ batch, logs });
|
|
9
|
+
process.exit(0);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
rollback().catch((e: Error) => {
|
|
13
|
+
console.log("Error in rolling back", e.message);
|
|
14
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { getDb, createDb } from "..";
|
|
2
|
+
|
|
3
|
+
async function seed(): Promise<void> {
|
|
4
|
+
let db = getDb();
|
|
5
|
+
try {
|
|
6
|
+
if (!db) db = createDb();
|
|
7
|
+
await db.seed.run();
|
|
8
|
+
process.exit(0);
|
|
9
|
+
} catch (error) {
|
|
10
|
+
throw error;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
seed().catch((e: Error) => {
|
|
15
|
+
console.error(`Error in running seeds`, e.message);
|
|
16
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@mini-yt/typescript-config/base.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rootDir": "src",
|
|
5
|
+
"outDir": "dist",
|
|
6
|
+
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": true,
|
|
9
|
+
|
|
10
|
+
"noEmit": false,
|
|
11
|
+
|
|
12
|
+
"module": "es2015",
|
|
13
|
+
"moduleResolution": "bundler",
|
|
14
|
+
|
|
15
|
+
"types": ["node"]
|
|
16
|
+
},
|
|
17
|
+
"include": ["src", "src/scripts"]
|
|
18
|
+
}
|