@loomcore/api 0.1.51 → 0.1.53
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/LICENSE +201 -201
- package/README.md +49 -49
- package/dist/__tests__/postgres-test-migrations/100-create-test-entities-table.migration.js +22 -22
- package/dist/__tests__/postgres-test-migrations/101-create-categories-table.migration.js +12 -12
- package/dist/__tests__/postgres-test-migrations/102-create-products-table.migration.js +21 -21
- package/dist/__tests__/postgres-test-migrations/103-create-test-items-table.migration.js +20 -20
- package/dist/__tests__/postgres.test-database.js +8 -8
- package/dist/databases/migrations/migration-runner.d.ts +3 -1
- package/dist/databases/migrations/migration-runner.js +90 -42
- package/dist/databases/mongo-db/migrations/mongo-foundational.d.ts +12 -0
- package/dist/databases/mongo-db/migrations/mongo-foundational.js +30 -0
- package/dist/databases/postgres/commands/postgres-batch-update.command.js +7 -7
- package/dist/databases/postgres/commands/postgres-create-many.command.js +10 -10
- package/dist/databases/postgres/commands/postgres-create.command.js +4 -4
- package/dist/databases/postgres/commands/postgres-full-update-by-id.command.js +13 -13
- package/dist/databases/postgres/commands/postgres-partial-update-by-id.command.js +7 -7
- package/dist/databases/postgres/commands/postgres-update.command.js +7 -7
- package/dist/databases/postgres/migrations/001-create-migrations-table.migration.js +12 -12
- package/dist/databases/postgres/migrations/002-create-organizations-table.migration.js +24 -24
- package/dist/databases/postgres/migrations/003-create-users-table.migration.js +26 -26
- package/dist/databases/postgres/migrations/004-create-refresh-tokens-table.migration.js +18 -18
- package/dist/databases/postgres/migrations/005-create-meta-org.migration.js +9 -9
- package/dist/databases/postgres/migrations/006-create-admin-user.migration.js +3 -3
- package/dist/databases/postgres/migrations/007-create-roles-table.migration.js +14 -14
- package/dist/databases/postgres/migrations/008-create-user-roles-table.migration.js +24 -24
- package/dist/databases/postgres/migrations/009-create-features-table.migration.js +14 -14
- package/dist/databases/postgres/migrations/010-create-authorizations-table.migration.js +26 -26
- package/dist/databases/postgres/migrations/011-create-admin-authorization.migration.js +44 -44
- package/dist/databases/postgres/migrations/database-builder.js +4 -4
- package/dist/databases/postgres/migrations/postgres-foundational.d.ts +12 -0
- package/dist/databases/postgres/migrations/postgres-foundational.js +47 -0
- package/dist/databases/postgres/postgres.database.js +17 -17
- package/dist/databases/postgres/utils/build-select-clause.js +6 -6
- package/dist/databases/postgres/utils/does-table-exist.util.js +4 -4
- package/package.json +88 -88
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Pool } from 'pg';
|
|
2
|
+
import { IBaseApiConfig } from '../../../models/base-api-config.interface.js';
|
|
3
|
+
export interface SyntheticMigration {
|
|
4
|
+
name: string;
|
|
5
|
+
up: (context: {
|
|
6
|
+
context: Pool;
|
|
7
|
+
}) => Promise<void>;
|
|
8
|
+
down: (context: {
|
|
9
|
+
context: Pool;
|
|
10
|
+
}) => Promise<void>;
|
|
11
|
+
}
|
|
12
|
+
export declare const getPostgresFoundational: (config: IBaseApiConfig) => SyntheticMigration[];
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export const getPostgresFoundational = (config) => {
|
|
2
|
+
const migrations = [];
|
|
3
|
+
const isMultiTenant = config.app.isMultiTenant === true;
|
|
4
|
+
migrations.push({
|
|
5
|
+
name: '00000000000001_base-users',
|
|
6
|
+
up: async ({ context: pool }) => {
|
|
7
|
+
const orgColumnDef = isMultiTenant ? '_orgId INTEGER,' : '';
|
|
8
|
+
const sql = `
|
|
9
|
+
CREATE TABLE users (
|
|
10
|
+
_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
11
|
+
${orgColumnDef}
|
|
12
|
+
email VARCHAR(255) NOT NULL UNIQUE,
|
|
13
|
+
password VARCHAR(255),
|
|
14
|
+
roles TEXT[],
|
|
15
|
+
created_at TIMESTAMP DEFAULT NOW(),
|
|
16
|
+
updated_at TIMESTAMP DEFAULT NOW()
|
|
17
|
+
);
|
|
18
|
+
`;
|
|
19
|
+
await pool.query(sql);
|
|
20
|
+
if (isMultiTenant) {
|
|
21
|
+
await pool.query(`CREATE INDEX idx_users_org_id ON users (_orgId);`);
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
down: async ({ context: pool }) => {
|
|
25
|
+
await pool.query('DROP TABLE IF EXISTS users');
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
if (isMultiTenant) {
|
|
29
|
+
migrations.push({
|
|
30
|
+
name: '00000000000002_base-organizations',
|
|
31
|
+
up: async ({ context: pool }) => {
|
|
32
|
+
await pool.query(`
|
|
33
|
+
CREATE TABLE organizations (
|
|
34
|
+
_id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
35
|
+
name VARCHAR(255) NOT NULL,
|
|
36
|
+
plan_tier VARCHAR(50) DEFAULT 'free',
|
|
37
|
+
created_at TIMESTAMP DEFAULT NOW()
|
|
38
|
+
);
|
|
39
|
+
`);
|
|
40
|
+
},
|
|
41
|
+
down: async ({ context: pool }) => {
|
|
42
|
+
await pool.query('DROP TABLE IF EXISTS organizations');
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return migrations;
|
|
47
|
+
};
|
|
@@ -68,23 +68,23 @@ export class PostgresDatabase {
|
|
|
68
68
|
}
|
|
69
69
|
async getUserAuthorizations(userId, orgId) {
|
|
70
70
|
const now = new Date();
|
|
71
|
-
let query = `
|
|
72
|
-
SELECT DISTINCT
|
|
73
|
-
ur."userId" as "userId",
|
|
74
|
-
r."name" as "role",
|
|
75
|
-
f."name" as "feature",
|
|
76
|
-
a."config",
|
|
77
|
-
a."_id",
|
|
78
|
-
a."_orgId"
|
|
79
|
-
FROM "user_roles" ur
|
|
80
|
-
INNER JOIN "roles" r ON ur."roleId" = r."_id"
|
|
81
|
-
INNER JOIN "authorizations" a ON r."_id" = a."roleId"
|
|
82
|
-
INNER JOIN "features" f ON a."featureId" = f."_id"
|
|
83
|
-
WHERE ur."userId" = $1
|
|
84
|
-
AND ur."_deleted" IS NULL
|
|
85
|
-
AND a."_deleted" IS NULL
|
|
86
|
-
AND (a."startDate" IS NULL OR a."startDate" <= $2)
|
|
87
|
-
AND (a."endDate" IS NULL OR a."endDate" >= $2)
|
|
71
|
+
let query = `
|
|
72
|
+
SELECT DISTINCT
|
|
73
|
+
ur."userId" as "userId",
|
|
74
|
+
r."name" as "role",
|
|
75
|
+
f."name" as "feature",
|
|
76
|
+
a."config",
|
|
77
|
+
a."_id",
|
|
78
|
+
a."_orgId"
|
|
79
|
+
FROM "user_roles" ur
|
|
80
|
+
INNER JOIN "roles" r ON ur."roleId" = r."_id"
|
|
81
|
+
INNER JOIN "authorizations" a ON r."_id" = a."roleId"
|
|
82
|
+
INNER JOIN "features" f ON a."featureId" = f."_id"
|
|
83
|
+
WHERE ur."userId" = $1
|
|
84
|
+
AND ur."_deleted" IS NULL
|
|
85
|
+
AND a."_deleted" IS NULL
|
|
86
|
+
AND (a."startDate" IS NULL OR a."startDate" <= $2)
|
|
87
|
+
AND (a."endDate" IS NULL OR a."endDate" >= $2)
|
|
88
88
|
`;
|
|
89
89
|
const values = [userId, now];
|
|
90
90
|
if (orgId) {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Join } from '../../operations/join.operation.js';
|
|
2
2
|
async function getTableColumns(client, tableName) {
|
|
3
|
-
const result = await client.query(`
|
|
4
|
-
SELECT column_name
|
|
5
|
-
FROM information_schema.columns
|
|
6
|
-
WHERE table_schema = current_schema()
|
|
7
|
-
AND table_name = $1
|
|
8
|
-
ORDER BY ordinal_position
|
|
3
|
+
const result = await client.query(`
|
|
4
|
+
SELECT column_name
|
|
5
|
+
FROM information_schema.columns
|
|
6
|
+
WHERE table_schema = current_schema()
|
|
7
|
+
AND table_name = $1
|
|
8
|
+
ORDER BY ordinal_position
|
|
9
9
|
`, [tableName]);
|
|
10
10
|
return result.rows.map(row => row.column_name);
|
|
11
11
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export async function doesTableExist(client, tableName) {
|
|
2
|
-
const result = await client.query(`
|
|
3
|
-
SELECT EXISTS (
|
|
4
|
-
SELECT 1 FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = $1
|
|
5
|
-
)
|
|
2
|
+
const result = await client.query(`
|
|
3
|
+
SELECT EXISTS (
|
|
4
|
+
SELECT 1 FROM information_schema.tables WHERE table_schema = current_schema() AND table_name = $1
|
|
5
|
+
)
|
|
6
6
|
`, [tableName]);
|
|
7
7
|
return result.rows[0].exists;
|
|
8
8
|
}
|
package/package.json
CHANGED
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@loomcore/api",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"private": false,
|
|
5
|
-
"description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"clean": "rm -rf dist",
|
|
8
|
-
"tsc": "tsc --project tsconfig.prod.json",
|
|
9
|
-
"build": "npm-run-all -s clean tsc",
|
|
10
|
-
"add": "git add .",
|
|
11
|
-
"commit": "git commit -m \"Updates\"",
|
|
12
|
-
"patch": "npm version patch",
|
|
13
|
-
"push": "git push",
|
|
14
|
-
"publishMe": "npm publish --access public",
|
|
15
|
-
"pub": "npm-run-all -s add commit patch build push publishMe",
|
|
16
|
-
"update-lib-versions": "npx --yes npm-check-updates -u -f @loomcore/common",
|
|
17
|
-
"install-updated-libs": "npm i @loomcore/common",
|
|
18
|
-
"update-libs": "npm-run-all -s update-lib-versions install-updated-libs",
|
|
19
|
-
"typecheck": "tsc",
|
|
20
|
-
"test": "npm-run-all -s test:postgres test:mongodb",
|
|
21
|
-
"test:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run",
|
|
22
|
-
"test:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run",
|
|
23
|
-
"test:ci": "npm-run-all -s test:ci:postgres test:ci:mongodb",
|
|
24
|
-
"test:ci:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --reporter=json --outputFile=test-results-postgres.json",
|
|
25
|
-
"test:ci:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --reporter=json --outputFile=test-results-mongodb.json",
|
|
26
|
-
"test:watch": "cross-env NODE_ENV=test vitest",
|
|
27
|
-
"coverage": "npm-run-all -s coverage:postgres coverage:mongodb",
|
|
28
|
-
"coverage:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --coverage",
|
|
29
|
-
"coverage:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --coverage"
|
|
30
|
-
},
|
|
31
|
-
"author": "Tim Hardy",
|
|
32
|
-
"license": "Apache 2.0",
|
|
33
|
-
"main": "dist/index.js",
|
|
34
|
-
"type": "module",
|
|
35
|
-
"types": "dist/index.d.ts",
|
|
36
|
-
"files": [
|
|
37
|
-
"dist/**/*"
|
|
38
|
-
],
|
|
39
|
-
"exports": {
|
|
40
|
-
"./__tests__": "./dist/__tests__/index.js",
|
|
41
|
-
"./config": "./dist/config/index.js",
|
|
42
|
-
"./controllers": "./dist/controllers/index.js",
|
|
43
|
-
"./databases": "./dist/databases/index.js",
|
|
44
|
-
"./errors": "./dist/errors/index.js",
|
|
45
|
-
"./middleware": "./dist/middleware/index.js",
|
|
46
|
-
"./models": "./dist/models/index.js",
|
|
47
|
-
"./services": "./dist/services/index.js",
|
|
48
|
-
"./utils": "./dist/utils/index.js"
|
|
49
|
-
},
|
|
50
|
-
"dependencies": {
|
|
51
|
-
"jsonwebtoken": "^9.0.2",
|
|
52
|
-
"node-mailjet": "^6.0.8",
|
|
53
|
-
"qs": "^6.14.0"
|
|
54
|
-
},
|
|
55
|
-
"peerDependencies": {
|
|
56
|
-
"@loomcore/common": "^0.0.32",
|
|
57
|
-
"@sinclair/typebox": "0.34.33",
|
|
58
|
-
"cookie-parser": "^1.4.6",
|
|
59
|
-
"cors": "^2.8.5",
|
|
60
|
-
"express": "^5.1.0",
|
|
61
|
-
"lodash": "^4.17.21",
|
|
62
|
-
"moment": "^2.30.1",
|
|
63
|
-
"mongodb": "^6.16.0",
|
|
64
|
-
"pg": "^8.15.6",
|
|
65
|
-
"rxjs": "^7.8.0",
|
|
66
|
-
"umzug": "^3.8.2"
|
|
67
|
-
},
|
|
68
|
-
"devDependencies": {
|
|
69
|
-
"@types/cookie-parser": "^1.4.7",
|
|
70
|
-
"@types/cors": "^2.8.18",
|
|
71
|
-
"@types/express": "^5.0.1",
|
|
72
|
-
"@types/jsonwebtoken": "^9.0.9",
|
|
73
|
-
"@types/lodash": "^4.17.13",
|
|
74
|
-
"@types/pg": "^8.15.6",
|
|
75
|
-
"@types/qs": "^6.14.0",
|
|
76
|
-
"@types/supertest": "^6.0.3",
|
|
77
|
-
"@vitest/coverage-v8": "^3.0.9",
|
|
78
|
-
"cross-env": "^7.0.3",
|
|
79
|
-
"mongodb-memory-server": "^9.3.0",
|
|
80
|
-
"npm-run-all": "^4.1.5",
|
|
81
|
-
"pg-mem": "^3.0.5",
|
|
82
|
-
"rxjs": "^7.8.0",
|
|
83
|
-
"supertest": "^7.1.0",
|
|
84
|
-
"typescript": "^5.8.3",
|
|
85
|
-
"vite": "^6.2.5",
|
|
86
|
-
"vitest": "^3.0.9"
|
|
87
|
-
}
|
|
88
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@loomcore/api",
|
|
3
|
+
"version": "0.1.53",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Loom Core Api - An opinionated Node.js api using Typescript, Express, and MongoDb or PostgreSQL",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"clean": "rm -rf dist",
|
|
8
|
+
"tsc": "tsc --project tsconfig.prod.json",
|
|
9
|
+
"build": "npm-run-all -s clean tsc",
|
|
10
|
+
"add": "git add .",
|
|
11
|
+
"commit": "git commit -m \"Updates\"",
|
|
12
|
+
"patch": "npm version patch",
|
|
13
|
+
"push": "git push",
|
|
14
|
+
"publishMe": "npm publish --access public",
|
|
15
|
+
"pub": "npm-run-all -s add commit patch build push publishMe",
|
|
16
|
+
"update-lib-versions": "npx --yes npm-check-updates -u -f @loomcore/common",
|
|
17
|
+
"install-updated-libs": "npm i @loomcore/common",
|
|
18
|
+
"update-libs": "npm-run-all -s update-lib-versions install-updated-libs",
|
|
19
|
+
"typecheck": "tsc",
|
|
20
|
+
"test": "npm-run-all -s test:postgres test:mongodb",
|
|
21
|
+
"test:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run",
|
|
22
|
+
"test:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run",
|
|
23
|
+
"test:ci": "npm-run-all -s test:ci:postgres test:ci:mongodb",
|
|
24
|
+
"test:ci:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --reporter=json --outputFile=test-results-postgres.json",
|
|
25
|
+
"test:ci:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --reporter=json --outputFile=test-results-mongodb.json",
|
|
26
|
+
"test:watch": "cross-env NODE_ENV=test vitest",
|
|
27
|
+
"coverage": "npm-run-all -s coverage:postgres coverage:mongodb",
|
|
28
|
+
"coverage:postgres": "cross-env NODE_ENV=test TEST_DATABASE=postgres vitest run --coverage",
|
|
29
|
+
"coverage:mongodb": "cross-env NODE_ENV=test TEST_DATABASE=mongodb vitest run --coverage"
|
|
30
|
+
},
|
|
31
|
+
"author": "Tim Hardy",
|
|
32
|
+
"license": "Apache 2.0",
|
|
33
|
+
"main": "dist/index.js",
|
|
34
|
+
"type": "module",
|
|
35
|
+
"types": "dist/index.d.ts",
|
|
36
|
+
"files": [
|
|
37
|
+
"dist/**/*"
|
|
38
|
+
],
|
|
39
|
+
"exports": {
|
|
40
|
+
"./__tests__": "./dist/__tests__/index.js",
|
|
41
|
+
"./config": "./dist/config/index.js",
|
|
42
|
+
"./controllers": "./dist/controllers/index.js",
|
|
43
|
+
"./databases": "./dist/databases/index.js",
|
|
44
|
+
"./errors": "./dist/errors/index.js",
|
|
45
|
+
"./middleware": "./dist/middleware/index.js",
|
|
46
|
+
"./models": "./dist/models/index.js",
|
|
47
|
+
"./services": "./dist/services/index.js",
|
|
48
|
+
"./utils": "./dist/utils/index.js"
|
|
49
|
+
},
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"jsonwebtoken": "^9.0.2",
|
|
52
|
+
"node-mailjet": "^6.0.8",
|
|
53
|
+
"qs": "^6.14.0"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@loomcore/common": "^0.0.32",
|
|
57
|
+
"@sinclair/typebox": "0.34.33",
|
|
58
|
+
"cookie-parser": "^1.4.6",
|
|
59
|
+
"cors": "^2.8.5",
|
|
60
|
+
"express": "^5.1.0",
|
|
61
|
+
"lodash": "^4.17.21",
|
|
62
|
+
"moment": "^2.30.1",
|
|
63
|
+
"mongodb": "^6.16.0",
|
|
64
|
+
"pg": "^8.15.6",
|
|
65
|
+
"rxjs": "^7.8.0",
|
|
66
|
+
"umzug": "^3.8.2"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@types/cookie-parser": "^1.4.7",
|
|
70
|
+
"@types/cors": "^2.8.18",
|
|
71
|
+
"@types/express": "^5.0.1",
|
|
72
|
+
"@types/jsonwebtoken": "^9.0.9",
|
|
73
|
+
"@types/lodash": "^4.17.13",
|
|
74
|
+
"@types/pg": "^8.15.6",
|
|
75
|
+
"@types/qs": "^6.14.0",
|
|
76
|
+
"@types/supertest": "^6.0.3",
|
|
77
|
+
"@vitest/coverage-v8": "^3.0.9",
|
|
78
|
+
"cross-env": "^7.0.3",
|
|
79
|
+
"mongodb-memory-server": "^9.3.0",
|
|
80
|
+
"npm-run-all": "^4.1.5",
|
|
81
|
+
"pg-mem": "^3.0.5",
|
|
82
|
+
"rxjs": "^7.8.0",
|
|
83
|
+
"supertest": "^7.1.0",
|
|
84
|
+
"typescript": "^5.8.3",
|
|
85
|
+
"vite": "^6.2.5",
|
|
86
|
+
"vitest": "^3.0.9"
|
|
87
|
+
}
|
|
88
|
+
}
|