@evenicanpm/portal-db 1.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/.env.example +4 -0
- package/README.md +58 -0
- package/package.json +30 -0
- package/src/db/db.ts +39 -0
- package/src/db/index.ts +48 -0
- package/src/db/migrations/20260122010359_uda.sql +63 -0
- package/src/index.ts +1 -0
- package/tsconfig.json +28 -0
package/.env.example
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# e4-Admin-Database-Product
|
|
2
|
+
|
|
3
|
+
This repository contains the database schema and PostgreSQL migration scripts for the admin panel.
|
|
4
|
+
All database migrations are managed using [Dbmate](https://github.com/amacneil/dbmate), a lightweight, language-agnostic migration tool.
|
|
5
|
+
|
|
6
|
+
## 🚀 Getting Started
|
|
7
|
+
|
|
8
|
+
Make sure the following tools are installed:
|
|
9
|
+
|
|
10
|
+
#### 1. PostgreSQL
|
|
11
|
+
|
|
12
|
+
#### 2. Dbmate
|
|
13
|
+
|
|
14
|
+
#### Install Dbmate on Linux (Ubuntu/Debian)
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
# Download the latest Dbmate binary
|
|
18
|
+
curl -fsSL https://github.com/amacneil/dbmate/releases/latest/download/dbmate-linux-amd64 -o dbmate
|
|
19
|
+
|
|
20
|
+
# Make it executable
|
|
21
|
+
chmod +x dbmate
|
|
22
|
+
|
|
23
|
+
# Move to a directory in your PATH
|
|
24
|
+
sudo mv dbmate /usr/local/bin/
|
|
25
|
+
|
|
26
|
+
# Check version
|
|
27
|
+
dbmate --version
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Migrations
|
|
31
|
+
|
|
32
|
+
#### 1. Create a new migration
|
|
33
|
+
|
|
34
|
+
dbmate new <migration_name>
|
|
35
|
+
This will generate a new migration file.
|
|
36
|
+
Add both migrate:up and migrate:down scripts to the file.
|
|
37
|
+
|
|
38
|
+
#### 2. Run migrations
|
|
39
|
+
|
|
40
|
+
Make sure DATABASE_URL is added to .env file. Copy over from the .env.example file.
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# To create the database (if it does not already exist) and run any pending migrations
|
|
44
|
+
dbmate -e "DATABASE_URL" up
|
|
45
|
+
|
|
46
|
+
# To run any pending migrations
|
|
47
|
+
dbmate -e "DATABASE_URL" migrate
|
|
48
|
+
|
|
49
|
+
# To roll back the most recent migration
|
|
50
|
+
dbmate -e "DATABASE_URL" rollback or dbmate -e "DATABASE_URL" down
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Alternatively, instead of reading DATABASE_URL from .env, you can specify the URL directly.
|
|
54
|
+
Like this:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
dbmate -u "postgres://username:password@host:port/database_name?sslmode=disable" up
|
|
58
|
+
```
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@evenicanpm/portal-db",
|
|
3
|
+
"version": "1.4.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"kysely-codegen": "kysely-codegen",
|
|
10
|
+
"build": "npx tsc",
|
|
11
|
+
"format": "npx @biomejs/biome format --write ./src"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./src/index.ts"
|
|
15
|
+
},
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@types/pg": "^8.16.0",
|
|
19
|
+
"kysely-codegen": "^0.19.0",
|
|
20
|
+
"tsx": "^4.21.0",
|
|
21
|
+
"typedoc": "^0.28.15",
|
|
22
|
+
"typedoc-github-theme": "^0.3.1",
|
|
23
|
+
"typescript": "^5.6.3"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"kysely": "^0.28.10",
|
|
27
|
+
"pg": "^8.17.2"
|
|
28
|
+
},
|
|
29
|
+
"gitHead": "0614726ec6b7ce9564706514a6b756b390a13e96"
|
|
30
|
+
}
|
package/src/db/db.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file was generated by kysely-codegen.
|
|
3
|
+
* Please do not edit it manually.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { ColumnType } from "kysely";
|
|
7
|
+
|
|
8
|
+
export type Generated<T> =
|
|
9
|
+
T extends ColumnType<infer S, infer I, infer U>
|
|
10
|
+
? ColumnType<S, I | undefined, U>
|
|
11
|
+
: ColumnType<T, T | undefined, T>;
|
|
12
|
+
|
|
13
|
+
export type JsonArray = JsonValue[];
|
|
14
|
+
|
|
15
|
+
export type JsonObject = {
|
|
16
|
+
[x: string]: JsonValue | undefined;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type JsonPrimitive = boolean | number | string | null;
|
|
20
|
+
|
|
21
|
+
export type JsonValue = JsonArray | JsonObject | JsonPrimitive;
|
|
22
|
+
|
|
23
|
+
export type Timestamp = ColumnType<Date, Date | string, Date | string>;
|
|
24
|
+
|
|
25
|
+
export interface SchemaMigrations {
|
|
26
|
+
version: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface UdaViewconfig {
|
|
30
|
+
columns: Generated<JsonValue>;
|
|
31
|
+
createdat: Generated<Timestamp | null>;
|
|
32
|
+
id: Generated<number>;
|
|
33
|
+
resource_name: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface DB {
|
|
37
|
+
schema_migrations: SchemaMigrations;
|
|
38
|
+
"uda.viewconfig": UdaViewconfig;
|
|
39
|
+
}
|
package/src/db/index.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// packages/uda-billing/src/db.ts
|
|
2
|
+
|
|
3
|
+
import { Kysely, type PostgresDialect, sql } from "kysely";
|
|
4
|
+
import type { DB, JsonValue } from "./db";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Portal service for view config db related queries
|
|
8
|
+
* @param dialect
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
const createPortalService = (dialect: PostgresDialect) => {
|
|
12
|
+
const db = new Kysely<DB>({ dialect });
|
|
13
|
+
return {
|
|
14
|
+
find: async (input: { resourceKey: string }) => {
|
|
15
|
+
return await db
|
|
16
|
+
.selectFrom("uda.viewconfig")
|
|
17
|
+
.selectAll()
|
|
18
|
+
.where("resource_name", "=", input?.resourceKey)
|
|
19
|
+
.executeTakeFirst();
|
|
20
|
+
},
|
|
21
|
+
findAll: async () => {
|
|
22
|
+
return await db
|
|
23
|
+
.selectFrom("uda.viewconfig")
|
|
24
|
+
.selectAll()
|
|
25
|
+
.orderBy("resource_name", "asc")
|
|
26
|
+
.execute();
|
|
27
|
+
},
|
|
28
|
+
upsert: async (input: { resourceKey: string; columns: JsonValue }) => {
|
|
29
|
+
const columnsJson = JSON.stringify(input.columns);
|
|
30
|
+
return await db
|
|
31
|
+
.insertInto("uda.viewconfig")
|
|
32
|
+
.values({
|
|
33
|
+
resource_name: input.resourceKey,
|
|
34
|
+
columns: sql`${columnsJson}::jsonb`,
|
|
35
|
+
})
|
|
36
|
+
.onConflict((oc) =>
|
|
37
|
+
oc.column("resource_name").doUpdateSet({
|
|
38
|
+
columns: sql`${columnsJson}::jsonb`,
|
|
39
|
+
}),
|
|
40
|
+
)
|
|
41
|
+
.returningAll()
|
|
42
|
+
.executeTakeFirst();
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export { createPortalService as portalService };
|
|
48
|
+
export type { DB };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
-- migrate:up
|
|
2
|
+
CREATE SCHEMA IF NOT EXISTS uda;
|
|
3
|
+
|
|
4
|
+
CREATE TABLE uda.viewconfig (
|
|
5
|
+
id SERIAL PRIMARY KEY,
|
|
6
|
+
resource_name text NOT NULL UNIQUE,
|
|
7
|
+
columns jsonb NOT NULL DEFAULT '[]',
|
|
8
|
+
createdat timestamptz DEFAULT now()
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
-- Seed Data
|
|
12
|
+
INSERT INTO uda.viewconfig (resource_name, columns)
|
|
13
|
+
VALUES (
|
|
14
|
+
'invoice',
|
|
15
|
+
'{
|
|
16
|
+
"Columns": [
|
|
17
|
+
{"Label":"Document ID","Data":"id","DataType":"numeric","DisplayOrder":1,"IsSearchable":false,"ColumnOrder":1},
|
|
18
|
+
{"Label":"Title","Data":"Title","DataType":"String","DisplayOrder":2,"IsSearchable":true,"ColumnOrder":2},
|
|
19
|
+
{
|
|
20
|
+
"Label": "Status",
|
|
21
|
+
"Data": "Status",
|
|
22
|
+
"DataType": "String",
|
|
23
|
+
"DisplayOrder": 3,
|
|
24
|
+
"IsSearchable": false,
|
|
25
|
+
"ColumnOrder": 3,
|
|
26
|
+
"IsFilterable": true,
|
|
27
|
+
"Filters": [
|
|
28
|
+
{
|
|
29
|
+
"FilterOptions": [
|
|
30
|
+
{"value": 2, "label": "Overdue"},
|
|
31
|
+
{"value": 0, "label": "Paid"},
|
|
32
|
+
{"value": 1, "label": "Due"}
|
|
33
|
+
],
|
|
34
|
+
"FilterOperation": "eq",
|
|
35
|
+
"FilterType": "select"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
{"Label":"Created Date","Data":"created","DataType":"datetime","DataMask":"MM/DD/YYYY","IsSearchable":false,"DisplayOrder":3,"ColumnOrder":3},
|
|
40
|
+
{"Label":"Document Type","Data":"document_type","DataType":"String","DisplayOrder":4,"IsSearchable":false,"ColumnOrder":4}
|
|
41
|
+
],
|
|
42
|
+
"Actions": [
|
|
43
|
+
{ "Name": "Download", "Type": "download", "IdField": "id" }
|
|
44
|
+
]
|
|
45
|
+
}'
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
INSERT INTO uda.viewconfig (resource_name, columns)
|
|
50
|
+
VALUES (
|
|
51
|
+
'statement',
|
|
52
|
+
'[
|
|
53
|
+
{"Label": "Statement ID", "Data": "statement_id", "DataType": "numeric", "DisplayOrder": 1, "ColumnOrder": 1},
|
|
54
|
+
{"Label": "Statement Date", "Data": "statement_date", "DataType": "datetime", "DataMask": "MM/DD/YYYY", "DisplayOrder": 2, "ColumnOrder": 2},
|
|
55
|
+
{"Label": "Customer Name", "Data": "customer_name", "DataType": "String", "DisplayOrder": 3, "IsSearchable": true, "ColumnOrder": 3},
|
|
56
|
+
{"Label": "Account Number", "Data": "account_number", "DataType": "String", "DisplayOrder": 4, "ColumnOrder": 4},
|
|
57
|
+
{"Label": "Balance Due", "Data": "balance_due", "DataType": "currency", "DisplayOrder": 5, "ColumnOrder": 5},
|
|
58
|
+
{"Label": "Statement Period", "Data": "statement_period", "DataType": "String", "DisplayOrder": 6, "ColumnOrder": 6},
|
|
59
|
+
{"Label": "Status", "Data": "status", "DataType": "String", "DisplayOrder": 7, "ColumnOrder": 7}
|
|
60
|
+
]'
|
|
61
|
+
);
|
|
62
|
+
-- migrate:down
|
|
63
|
+
DROP TABLE IF EXISTS uda.viewconfig;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { type DB, portalService } from "./db";
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES6",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"sourceMap": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"declaration": true,
|
|
11
|
+
"preserveSymlinks": true,
|
|
12
|
+
"moduleResolution": "node",
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"isolatedModules": true,
|
|
15
|
+
"emitDeclarationOnly": true,
|
|
16
|
+
"jsx": "preserve",
|
|
17
|
+
"strict": true,
|
|
18
|
+
"noUnusedLocals": true,
|
|
19
|
+
"noUnusedParameters": true,
|
|
20
|
+
"noFallthroughCasesInSwitch": true,
|
|
21
|
+
"allowJs": true,
|
|
22
|
+
"forceConsistentCasingInFileNames": true,
|
|
23
|
+
"incremental": true,
|
|
24
|
+
"baseUrl": "./",
|
|
25
|
+
"outDir": "./dist"
|
|
26
|
+
},
|
|
27
|
+
"include": ["src"]
|
|
28
|
+
}
|