bd-orm 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.
Files changed (59) hide show
  1. package/.github/workflows/build-and-test.yml +26 -0
  2. package/.github/workflows/publish.yml +36 -0
  3. package/.prettierrc.json +14 -0
  4. package/CHANGELOG.md +3 -0
  5. package/README.md +5 -0
  6. package/check NBR en TODO.txt +32 -0
  7. package/dist/_/BdORMBase.d.ts +111 -0
  8. package/dist/_/BdORMBase.js +262 -0
  9. package/dist/_/BdORMCrud.d.ts +51 -0
  10. package/dist/_/BdORMCrud.js +223 -0
  11. package/dist/_/BdORMError.d.ts +4 -0
  12. package/dist/_/BdORMError.js +14 -0
  13. package/dist/_/BdOrmConnection.d.ts +32 -0
  14. package/dist/_/BdOrmConnection.js +5 -0
  15. package/dist/_/cdsBaseOrm.d.ts +12 -0
  16. package/dist/_/cdsBaseOrm.js +21 -0
  17. package/dist/dbConnections/BdOrmDbConnectionCapHana/index.d.ts +26 -0
  18. package/dist/dbConnections/BdOrmDbConnectionCapHana/index.js +78 -0
  19. package/dist/dbConnections/BdOrmDbConnectionCapHana/utils.d.ts +14 -0
  20. package/dist/dbConnections/BdOrmDbConnectionCapHana/utils.js +49 -0
  21. package/dist/dbConnections/BdOrmDbConnectionCapSqlite/index.d.ts +22 -0
  22. package/dist/dbConnections/BdOrmDbConnectionCapSqlite/index.js +85 -0
  23. package/dist/dbConnections/BdOrmDbConnectionCapSqlite/utils.d.ts +3 -0
  24. package/dist/dbConnections/BdOrmDbConnectionCapSqlite/utils.js +74 -0
  25. package/dist/dbConnections/BdOrmDbConnectionSQLBase.d.ts +32 -0
  26. package/dist/dbConnections/BdOrmDbConnectionSQLBase.js +99 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.js +18 -0
  29. package/dist/test-assets/Post.d.ts +12 -0
  30. package/dist/test-assets/Post.js +13 -0
  31. package/dist/test-assets/User.d.ts +16 -0
  32. package/dist/test-assets/User.js +13 -0
  33. package/dist/test-assets/jestUtils.d.ts +5 -0
  34. package/dist/test-assets/jestUtils.js +30 -0
  35. package/jest.config.js +7 -0
  36. package/package.json +53 -0
  37. package/src/_/BdORMBase.ts +288 -0
  38. package/src/_/BdORMCrud.test.ts +198 -0
  39. package/src/_/BdORMCrud.ts +240 -0
  40. package/src/_/BdORMError.ts +10 -0
  41. package/src/_/BdORMbase.test.ts +166 -0
  42. package/src/_/BdOrmConnection.ts +39 -0
  43. package/src/_/cdsBaseOrm.ts +18 -0
  44. package/src/dbConnections/BdOrmDbConnectionCapHana/index.ts +95 -0
  45. package/src/dbConnections/BdOrmDbConnectionCapHana/utils.ts +47 -0
  46. package/src/dbConnections/BdOrmDbConnectionCapHana.test.ts +18 -0
  47. package/src/dbConnections/BdOrmDbConnectionCapSqlite/index.ts +89 -0
  48. package/src/dbConnections/BdOrmDbConnectionCapSqlite/utils.ts +75 -0
  49. package/src/dbConnections/BdOrmDbConnectionCapSqlite.test.ts +41 -0
  50. package/src/dbConnections/BdOrmDbConnectionSQLBase.ts +124 -0
  51. package/src/index.ts +8 -0
  52. package/src/test-assets/Post.ts +16 -0
  53. package/src/test-assets/User.ts +18 -0
  54. package/src/test-assets/db/BdOrm.cds +20 -0
  55. package/src/test-assets/db/csv/bdorm-user.csv +3 -0
  56. package/src/test-assets/db/views/user.hdbview +3 -0
  57. package/src/test-assets/jestUtils.ts +24 -0
  58. package/tsconfig.json +16 -0
  59. package/validate-package.js +113 -0
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.deployHdbViewFiles = exports.log = exports.findFiles = exports.fillTableFromCsv = exports.addCsvFilesFromDBFolder = void 0;
7
+ const BdORMError_1 = require("../../_/BdORMError");
8
+ const csv_parser_1 = __importDefault(require("csv-parser"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const log = (message) => {
12
+ console.log(`[BdOrmDbConnectionCapSqlite] ${message}`);
13
+ }, fillTableFromCsv = async (db, table, csvFile) => {
14
+ try {
15
+ const rows = [];
16
+ await new Promise((resolve, reject) => {
17
+ fs_1.default.createReadStream(csvFile)
18
+ .pipe((0, csv_parser_1.default)({ separator: ';' }))
19
+ .on('data', (data) => rows.push(data))
20
+ .on('end', () => resolve())
21
+ .on('error', error => {
22
+ reject(error);
23
+ });
24
+ });
25
+ // empty db
26
+ await db.run(`DELETE FROM ${table}`);
27
+ for (const row of rows) {
28
+ const columns = Object.keys(row), placeholders = columns.map(() => '?').join(',');
29
+ await db.run(`INSERT INTO ${table} (${columns.join(', ')}) VALUES (${placeholders})`, Object.values(row));
30
+ }
31
+ log(`Added ${rows.length} rows in ${table} from CSV file: ${csvFile}`);
32
+ }
33
+ catch (error) {
34
+ throw new BdORMError_1.BdORMError(`Error while filling table from CSV: ${error.message}`);
35
+ }
36
+ }, findFiles = async (currentPath, extname) => {
37
+ let files = [];
38
+ //@ts-ignore
39
+ const entries = fs_1.default.readdirSync(currentPath, { withFileTypes: true });
40
+ //@ts-ignore
41
+ for (const entry of entries) {
42
+ const entryPath = path_1.default.join(currentPath, entry.name);
43
+ if (entry.isDirectory()) {
44
+ const subfiles = await findFiles(entryPath, extname);
45
+ files.push(...subfiles);
46
+ }
47
+ else if (entry.isFile() && path_1.default.extname(entry.name) === extname) {
48
+ files.push(entryPath);
49
+ }
50
+ }
51
+ return files;
52
+ }, addCsvFilesFromDBFolder = async (db, dbPath) => {
53
+ try {
54
+ const csvFiles = await findFiles(dbPath, '.csv');
55
+ for (const csvFile of csvFiles) {
56
+ await fillTableFromCsv(db, csvFile.split('/').pop()?.replace('.csv', '').replace('-', '_'), csvFile);
57
+ }
58
+ }
59
+ catch (error) {
60
+ throw new BdORMError_1.BdORMError(`Error while adding CsvFilesFromDbFolder: ${error.message}`);
61
+ }
62
+ }, deployHdbViewFiles = async (db, dbPath) => {
63
+ const hdbViewFiles = await findFiles(dbPath, '.hdbview');
64
+ for (const hdbViewFile of hdbViewFiles) {
65
+ const hdbView = fs_1.default.readFileSync(hdbViewFile, 'utf8');
66
+ const m = await db.run(`create ${hdbView}`);
67
+ log(`Deployed HDB view from file: ${hdbViewFile}`);
68
+ }
69
+ };
70
+ exports.log = log;
71
+ exports.fillTableFromCsv = fillTableFromCsv;
72
+ exports.findFiles = findFiles;
73
+ exports.addCsvFilesFromDBFolder = addCsvFilesFromDBFolder;
74
+ exports.deployHdbViewFiles = deployHdbViewFiles;
@@ -0,0 +1,32 @@
1
+ import BdOrmDbConnection from '../_/BdOrmConnection';
2
+ declare abstract class BdOrmDbConnectionSQLBase extends BdOrmDbConnection {
3
+ protected _db(): Promise<{
4
+ run: (query: string, values?: any[]) => Promise<any>;
5
+ }>;
6
+ close(): Promise<void>;
7
+ create(table: string, data: Record<string, any>): Promise<any>;
8
+ delete(table: string, primaryKeyValue: string | number): Promise<void>;
9
+ getTableColumns(table: string): Promise<string[]>;
10
+ /**
11
+ * Get the primary key of the table
12
+ */
13
+ getTablePrimaryKey(table: string): Promise<string>;
14
+ list(table: string, { filters, columns, orderBy, limit, offset, values, }?: {
15
+ columns?: string | string[];
16
+ filters?: Record<string, any> | string;
17
+ limit?: number;
18
+ offset?: number;
19
+ orderBy?: string;
20
+ values?: any[];
21
+ }): Promise<any>;
22
+ query(query: string, escapedValues?: any[]): Promise<any>;
23
+ /**
24
+ * Alias for query
25
+ */
26
+ run(query: string, escapedValues?: any[]): Promise<any>;
27
+ read(table: string, primaryKeyValue: string | number, { primaryKey }?: {
28
+ primaryKey?: string;
29
+ }): Promise<any>;
30
+ update(table: string, data: any): Promise<void>;
31
+ }
32
+ export default BdOrmDbConnectionSQLBase;
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ /**
7
+ * Use this class as a base class for all SQL database connections
8
+ * It provides methods to interact with the database, such as create, read, update, delete, and list records.
9
+ * It also provides methods to execute raw SQL queries and manage database connections.
10
+ *
11
+ * This class is not meant to be used directly, but rather as a base class for other database connection classes.
12
+ * make sure yo u implement the _db method to return the correct database connection
13
+ * and the getTableColumns and getTablePrimaryKey methods to return the correct table columns and primary key
14
+ */
15
+ const BdORMError_1 = require("../_/BdORMError");
16
+ const BdOrmConnection_1 = __importDefault(require("../_/BdOrmConnection"));
17
+ class BdOrmDbConnectionSQLBase extends BdOrmConnection_1.default {
18
+ async _db() {
19
+ throw new BdORMError_1.BdORMError(`_db not implemented for ${this.constructor.name}`);
20
+ }
21
+ async close() {
22
+ throw new BdORMError_1.BdORMError(`close not implemented for ${this.constructor.name}`);
23
+ }
24
+ async create(table, data) {
25
+ const columns = Object.keys(data), placeholders = columns.map(() => '?').join(',');
26
+ const { lastInsertRowid } = await this.query(`INSERT INTO ${table} (${columns.join(',')}) VALUES (${placeholders})`, columns.map(column => data[column]));
27
+ const pk = await this.getTablePrimaryKey(table);
28
+ const result = await this.query(`SELECT * FROM ${table} WHERE ${pk} = ${lastInsertRowid}`);
29
+ return result[0];
30
+ }
31
+ async delete(table, primaryKeyValue) {
32
+ const primaryKey = await this.getTablePrimaryKey(table);
33
+ await this.query(`DELETE FROM ${table} WHERE ${primaryKey} = ?`, [primaryKeyValue]);
34
+ }
35
+ async getTableColumns(table) {
36
+ throw new BdORMError_1.BdORMError(`getTableColumns not implemented for ${this.constructor.name}`);
37
+ }
38
+ /**
39
+ * Get the primary key of the table
40
+ */
41
+ async getTablePrimaryKey(table) {
42
+ throw new BdORMError_1.BdORMError(`getTablePrimaryKey not implemented for ${this.constructor.name}`);
43
+ }
44
+ async list(table, { filters, columns = '*', orderBy, limit, offset, values = [], } = {}) {
45
+ let query = `SELECT ${columns} FROM ${table}`;
46
+ if (typeof filters === 'string') {
47
+ query += ` WHERE ${filters}`;
48
+ }
49
+ else {
50
+ if (typeof filters === 'object' && Object.keys(filters).length > 0) {
51
+ values = [];
52
+ const whereClause = Object.keys(filters)
53
+ .map(key => `${key} = ?`)
54
+ .join(' AND ');
55
+ query += ` WHERE ${whereClause}`;
56
+ values.push(...Object.values(filters));
57
+ }
58
+ if (orderBy)
59
+ query += ` ORDER BY ${orderBy}`;
60
+ if (limit)
61
+ query += ` LIMIT ${limit}`;
62
+ if (offset)
63
+ query += ` OFFSET ${offset}`;
64
+ }
65
+ return this.query(query, values);
66
+ }
67
+ async query(query, escapedValues = []) {
68
+ const db = await this._db();
69
+ try {
70
+ return await db.run(query, escapedValues);
71
+ }
72
+ catch (error) {
73
+ throw new BdORMError_1.BdORMError(`Error executing db query: ${error?.message}. \nQuery: ${query} \nValues: ${escapedValues}`);
74
+ }
75
+ }
76
+ /**
77
+ * Alias for query
78
+ */
79
+ async run(query, escapedValues = []) {
80
+ return this.query(query, escapedValues);
81
+ }
82
+ async read(table, primaryKeyValue, { primaryKey } = {}) {
83
+ const pk = primaryKey ?? (await this.getTablePrimaryKey(table));
84
+ const result = await this.query(`SELECT * FROM ${table} WHERE ${pk} = ?`, [primaryKeyValue]);
85
+ return result?.[0] || undefined;
86
+ }
87
+ async update(table, data) {
88
+ const setClause = Object.keys(data)
89
+ .map(key => `${key} = ?`)
90
+ .join(', '), primaryKey = await this.getTablePrimaryKey(table), primaryKeyValue = data[primaryKey];
91
+ if (!primaryKeyValue)
92
+ throw new BdORMError_1.BdORMError(`No primary key value found for table ${table}, data: ${JSON.stringify(data)}`);
93
+ await this.query(`UPDATE ${table} SET ${setClause} WHERE ${primaryKey} = ?`, [
94
+ ...Object.values(data),
95
+ primaryKeyValue,
96
+ ]);
97
+ }
98
+ }
99
+ exports.default = BdOrmDbConnectionSQLBase;
@@ -0,0 +1,8 @@
1
+ import BdOrmDbConnectionCapSqlite from './dbConnections/BdOrmDbConnectionCapSqlite';
2
+ import BaseORMCrud from './_/BdORMCrud';
3
+ import BdOrmDbConnection from './_/BdOrmConnection';
4
+ import BdOrmDbConnectionCapHana from './dbConnections/BdOrmDbConnectionCapHana';
5
+ import BdOrmDbConnectionSQLBase from './dbConnections/BdOrmDbConnectionSQLBase';
6
+ export default class BdOrm extends BaseORMCrud {
7
+ }
8
+ export { BdOrmDbConnection, BdOrmDbConnectionCapSqlite, BdOrmDbConnectionCapHana, BdOrmDbConnectionSQLBase };
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.BdOrmDbConnectionSQLBase = exports.BdOrmDbConnectionCapHana = exports.BdOrmDbConnectionCapSqlite = exports.BdOrmDbConnection = void 0;
7
+ const BdOrmDbConnectionCapSqlite_1 = __importDefault(require("./dbConnections/BdOrmDbConnectionCapSqlite"));
8
+ exports.BdOrmDbConnectionCapSqlite = BdOrmDbConnectionCapSqlite_1.default;
9
+ const BdORMCrud_1 = __importDefault(require("./_/BdORMCrud"));
10
+ const BdOrmConnection_1 = __importDefault(require("./_/BdOrmConnection"));
11
+ exports.BdOrmDbConnection = BdOrmConnection_1.default;
12
+ const BdOrmDbConnectionCapHana_1 = __importDefault(require("./dbConnections/BdOrmDbConnectionCapHana"));
13
+ exports.BdOrmDbConnectionCapHana = BdOrmDbConnectionCapHana_1.default;
14
+ const BdOrmDbConnectionSQLBase_1 = __importDefault(require("./dbConnections/BdOrmDbConnectionSQLBase"));
15
+ exports.BdOrmDbConnectionSQLBase = BdOrmDbConnectionSQLBase_1.default;
16
+ class BdOrm extends BdORMCrud_1.default {
17
+ }
18
+ exports.default = BdOrm;
@@ -0,0 +1,12 @@
1
+ import BdOrm from '..';
2
+ interface Post {
3
+ id: number;
4
+ title: string;
5
+ content: string;
6
+ userId: number;
7
+ }
8
+ declare class Post extends BdOrm {
9
+ static readonly DB_TABLE: string;
10
+ fetchUser(): Promise<void>;
11
+ }
12
+ export default Post;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const __1 = __importDefault(require(".."));
7
+ class Post extends __1.default {
8
+ static DB_TABLE = 'posts';
9
+ async fetchUser() {
10
+ //TODO; //User.fetch
11
+ }
12
+ }
13
+ exports.default = Post;
@@ -0,0 +1,16 @@
1
+ import BdOrm from '..';
2
+ interface User {
3
+ id: number;
4
+ firstname: string;
5
+ lastname: string;
6
+ fullname?: string;
7
+ email: string;
8
+ dateCreated: string;
9
+ }
10
+ declare class User extends BdOrm {
11
+ static readonly DB_TABLE = "bdorm_user";
12
+ static readonly DB_VIEW = "user_view";
13
+ static readonly PROPERTIES_NOT_ALLOWED_TO_CHANGE: string[];
14
+ static readonly PROPERTIES_NOT_ALLOWED_TO_DUPLICATE: string[];
15
+ }
16
+ export default User;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const __1 = __importDefault(require(".."));
7
+ class User extends __1.default {
8
+ static DB_TABLE = 'bdorm_user';
9
+ static DB_VIEW = 'user_view';
10
+ static PROPERTIES_NOT_ALLOWED_TO_CHANGE = ['dateCreated'];
11
+ static PROPERTIES_NOT_ALLOWED_TO_DUPLICATE = ['dateCreated'];
12
+ }
13
+ exports.default = User;
@@ -0,0 +1,5 @@
1
+ export declare const expectErrorMessage: (fn: () => Promise<unknown>, message: string) => Promise<void>;
2
+ export declare const expectToBes: (tests: Record<string, {
3
+ test: () => any;
4
+ toBe: any;
5
+ }>) => void;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.expectToBes = exports.expectErrorMessage = void 0;
4
+ const globals_1 = require("@jest/globals");
5
+ const expectErrorMessage = async (fn, message) => {
6
+ try {
7
+ await fn();
8
+ //@ts-ignore
9
+ fail('Expected an error to be thrown');
10
+ }
11
+ catch (error) {
12
+ //@ts-ignore (excepct = jest)
13
+ if (error instanceof Error)
14
+ return (0, globals_1.expect)(error.message).toContain(message);
15
+ console.log(error);
16
+ //@ts-ignore (fail = jest fail)
17
+ fail('error is not of type Error');
18
+ }
19
+ };
20
+ exports.expectErrorMessage = expectErrorMessage;
21
+ const expectToBes = (tests) => {
22
+ Object.entries(tests).forEach(([title, { test, toBe }]) => {
23
+ (0, globals_1.it)(`${title} returns ${toBe}`, () => {
24
+ const value = test();
25
+ (0, globals_1.expect)(value).toBe(toBe);
26
+ (0, globals_1.expect)(value).not.toBe('RANDOM VALUE 1234567890');
27
+ });
28
+ });
29
+ };
30
+ exports.expectToBes = expectToBes;
package/jest.config.js ADDED
@@ -0,0 +1,7 @@
1
+ /** @type {import('jest').Config} */
2
+ module.exports = {
3
+ preset: 'ts-jest',
4
+ testEnvironment: 'node',
5
+ workerIdleMemoryLimit: '512MB',
6
+ roots: ['./src'],
7
+ };
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "bd-orm",
3
+ "version": "0.0.1",
4
+ "description": "NodeJS object-relational mapping (ORM)",
5
+ "author": "Barry Dam",
6
+ "main": "dist/index.js",
7
+ "exports": "./dist/index.js",
8
+ "types": "dist/index.d.ts",
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "prebuild": "rm -rf dist",
12
+ "test": "jest",
13
+ "validatePackageVersion": "node validate-package-version.js",
14
+ "version:bump": "npm version --git-tag-version=false patch",
15
+ "version:bump:major": "npm version --git-tag-version=false major",
16
+ "version:bump:minor": "npm version --git-tag-version=false minor",
17
+ "version:bump:beta": "npm version --git-tag-version=false --preid=beta prerelease",
18
+ "version:bump:next": "npm version --git-tag-version=false --preid=next prerelease"
19
+ },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/BarryDam/bdorm.git"
23
+ },
24
+ "keywords": [
25
+ "NodeJs",
26
+ "ORM",
27
+ "SQL",
28
+ "DB",
29
+ "Model"
30
+ ],
31
+ "license": "ISC",
32
+ "bugs": {
33
+ "url": "https://github.com/BarryDam/bdorm/issues"
34
+ },
35
+ "homepage": "https://github.com/BarryDam/bdorm#readme",
36
+ "devDependencies": {
37
+ "@actions/core": "^1.11.1",
38
+ "@cap-js/cds-types": "^0.10.0",
39
+ "@cap-js/sqlite": "^1.10.0",
40
+ "@sap/dev-cap-tools": "^1.44.1",
41
+ "@types/jest": "^29.5.14",
42
+ "@types/node": "^22.14.1",
43
+ "csv-parser": "^3.2.0",
44
+ "jest": "^29.7.0",
45
+ "prettier": "^3.5.3",
46
+ "semver": "^7.7.2",
47
+ "ts-jest": "^29.3.2",
48
+ "typescript": "^5.8.3"
49
+ },
50
+ "dependencies": {
51
+ "@sap/cds-dk": "^8.9.1"
52
+ }
53
+ }