├── .dockerignore ├── .env ├── .eslintrc.json ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── Dockerfile ├── LICENSE ├── README.md ├── config.yaml ├── package-lock.json ├── package.json ├── sql ├── create-schema.sql └── delete-schema.sql ├── src ├── config.ts ├── generator.ts ├── main.ts └── pg_schema │ ├── entities │ ├── Authors.ts │ ├── Books.ts │ ├── Courses.ts │ ├── CustomerOrders.ts │ ├── Customers.ts │ ├── DailySales.ts │ ├── Departments.ts │ ├── EmployeePerformance.ts │ ├── EmployeeProjects.ts │ ├── EmployeeSales.ts │ ├── Employees.ts │ ├── MonthlySales.ts │ ├── Movies.ts │ ├── OrderStatuses.ts │ ├── Orders.ts │ ├── ProductPrices.ts │ ├── ProductRevenue.ts │ ├── Products.ts │ ├── ProjectStages.ts │ ├── Projects.ts │ ├── Purchases.ts │ ├── Responses.ts │ ├── Salaries.ts │ ├── Sales.ts │ ├── SalesReps.ts │ ├── StudentGrades.ts │ ├── StudentScores.ts │ ├── Students.ts │ ├── Teams.ts │ ├── Transactions.ts │ ├── UserVisits.ts │ └── Users.ts │ ├── ormconfig.json │ └── tsconfig.json ├── test └── test.ts ├── tsconfig.build.json └── tsconfig.json /.dockerignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /dist -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | POSTGRES_USER=user 2 | POSTGRES_PASSWORD=password 3 | POSTGRES_DB=postgres 4 | POSTGRES_PORT=5432 -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "plugins": ["@typescript-eslint"], 4 | "rules": { 5 | "@typescript-eslint/explicit-function-return-type": "error" 6 | } 7 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /dist 2 | /node_modules -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "type": "node", 6 | "request": "launch", 7 | "name": "Launch Program", 8 | "skipFiles": [ "/**" ], 9 | "program": "${workspaceFolder}/dist/src/main.js", 10 | "cwd": "${workspaceFolder}", 11 | "console": "integratedTerminal", 12 | "preLaunchTask": "build", 13 | "envFile": "${workspaceFolder}/.env" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "build", 7 | "group": "build", 8 | "problemMatcher": [], 9 | "label": "build", 10 | "detail": "tsc --build" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | FROM node:21.7.3-slim 3 | WORKDIR /usr/src/app 4 | COPY . . 5 | RUN npm install && npm run build:prod && npm cache clean --force 6 | 7 | FROM node:21.7.3-slim 8 | RUN groupadd -r appuser && useradd -r -g appuser -s /sbin/nologin -d /usr/src/app appuser \ 9 | && mkdir -p /usr/src/app \ 10 | && chown -R appuser:appuser /usr/src/app 11 | 12 | WORKDIR /usr/src/app 13 | COPY --from=0 /usr/src/app/ ./ 14 | USER appuser 15 | EXPOSE 3000 16 | CMD ["npm", "run", "start:prod"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nodejs-dbgen 2 | Данная утилита сделана для тестирования и тренировки выполнения SQL запросов для базы данных Postgres. Её нужно использовать совместно с придуманными мною задачами на сайте [knowt.com](https://knowt.com/flashcards/8ccb3fe7-6631-4ded-9c58-fceb50b666da). Данный тренажёр пока включает в себя 69 задач на 30.09.2024 г. Я планирую расширять этот список, добавив как можно более экзотических вещей, которые можно выполнять с БД. 3 | 4 | С помощью этой утилиты вы можете синтезировать какое угодно количество данных, изменив config.yaml. (Если у вас мало место на диске, то будьте осторожны :D) 5 | 6 | Почему не использовать уже готовые сервисы для такого типа LeetCode? Вряд ли они позволят вам тестировать свои гипотизы на таблицах с более чем 10 000 000 7 | записей. Так вы сможете безопасно ломать эту базу и на практике убедится как оптимизировать запросы. 8 | 9 | ![image](https://github.com/user-attachments/assets/1e3dc209-d1e6-46cd-9356-ce0945fbcfb2) 10 | 11 | # Чтобы этим пользоваться вам понадобится 12 | ## Создать тестовый image pg в докере 13 | ```bash 14 | $ docker run --name testdb --env-file .env -p 5432:5432 -d postgres:latest 15 | ``` 16 | ## 17 | -------------------------------------------------------------------------------- /config.yaml: -------------------------------------------------------------------------------- 1 | users: 100 2 | sales: 100 3 | employees: 100 4 | departments: 10 5 | teams: 10 6 | orders: 100 7 | customers: 10 8 | books: 100 9 | authors: 10 10 | courses: 100 11 | students: 10 12 | transactions: 100 13 | student_grades: 100 14 | student_scores: 100 15 | responses: 100 16 | sales_reps: 100 17 | movies: 100 18 | purchases: 100 19 | products: 100 20 | projects: 100 21 | salaries: 100 22 | product_prices: 100 23 | order_statuses: 100 24 | project_stages: 100 25 | daily_sales: 100 26 | user_visits: 100 27 | monthly_sales: 100 28 | customer_orders: 100 29 | product_revenue: 100 30 | employee_sales: 100 31 | employee_projects: 100 32 | employee_performance: 100 33 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nodejs_console", 3 | "version": "1.0.0", 4 | "main": "main.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "build": "tsc --build", 8 | "build:prod": "npm run build && npm prune --omit=dev", 9 | "start:prod": "node dist/src/main.js", 10 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix", 11 | "typeorm:generate": "typeorm-model-generator -h localhost -d postgres -u user -x password -e postgres -o ./src/pg_schema" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "description": "", 16 | "devDependencies": { 17 | "@faker-js/faker": "^9.0.0", 18 | "@types/cli-progress": "^3.11.6", 19 | "@typescript-eslint/eslint-plugin": "^8.5.0", 20 | "@typescript-eslint/parser": "^8.5.0", 21 | "eslint": "^8.42.0", 22 | "typeorm-model-generator": "^0.4.6", 23 | "typescript": "^5.5.4" 24 | }, 25 | "dependencies": { 26 | "@types/js-yaml": "^4.0.9", 27 | "class-validator": "^0.14.1", 28 | "cli-progress": "^3.12.0", 29 | "dotenv": "^16.4.5", 30 | "js-yaml": "^4.1.0", 31 | "pg": "^8.12.0", 32 | "reflect-metadata": "^0.2.2", 33 | "typeorm": "^0.3.20" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /sql/create-schema.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | CREATE TABLE IF NOT EXISTS users ( 4 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 5 | username VARCHAR(50) NOT NULL, 6 | email VARCHAR(100) NOT NULL, 7 | password VARCHAR(255) NOT NULL 8 | ); 9 | 10 | CREATE TABLE IF NOT EXISTS products ( 11 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 12 | product_id INT, 13 | sales INT CHECK (sales >= 0) DEFAULT NULL 14 | ); 15 | 16 | CREATE TABLE IF NOT EXISTS sales ( 17 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 18 | product_id INT, 19 | sale_date TIMESTAMP DEFAULT NULL, 20 | amount INT CHECK (amount >= 0) DEFAULT NULL 21 | ); 22 | 23 | CREATE TABLE IF NOT EXISTS teams ( 24 | team_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 25 | team_name VARCHAR(255) DEFAULT NULL 26 | ); 27 | 28 | CREATE TABLE IF NOT EXISTS departments( 29 | department_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 30 | department_name VARCHAR(255) 31 | ); 32 | 33 | CREATE TABLE IF NOT EXISTS employees ( 34 | employee_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 35 | name VARCHAR(255) DEFAULT NULL, 36 | department VARCHAR(255) DEFAULT NULL, 37 | salary INT CHECK (salary >= 0) DEFAULT NULL, 38 | team_id INT REFERENCES teams(team_id) ON DELETE CASCADE ON UPDATE CASCADE, 39 | department_id INT REFERENCES departments(department_id) ON DELETE CASCADE ON UPDATE CASCADE 40 | ); 41 | 42 | CREATE TABLE IF NOT EXISTS customers( 43 | customer_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 44 | customer_name VARCHAR(255) 45 | ); 46 | 47 | CREATE TABLE IF NOT EXISTS orders ( 48 | order_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 49 | customer_id INT, 50 | amount INT CHECK (amount >= 0) DEFAULT NULL, 51 | order_date TIMESTAMP DEFAULT NULL, 52 | FOREIGN KEY (customer_id) REFERENCES customers(customer_id) ON DELETE CASCADE ON UPDATE CASCADE 53 | ); 54 | 55 | CREATE TABLE IF NOT EXISTS transactions ( 56 | transaction_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 57 | client_id INT CHECK (client_id >= 0) DEFAULT NULL, 58 | transaction_date TIMESTAMP DEFAULT NULL 59 | ); 60 | 61 | CREATE TABLE IF NOT EXISTS student_grades ( 62 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 63 | student_id INT, 64 | course_id INT CHECK (course_id >= 0) DEFAULT NULL, 65 | grade INT CHECK (grade >= 0) DEFAULT NULL 66 | ); 67 | 68 | CREATE TABLE IF NOT EXISTS responses ( 69 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 70 | employee_id INT CHECK (employee_id >= 0) DEFAULT NULL, 71 | response_time INT CHECK (response_time >= 0) DEFAULT NULL 72 | ); 73 | 74 | CREATE TABLE IF NOT EXISTS sales_reps ( 75 | sales_rep_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 76 | month DATE DEFAULT NULL, 77 | sales_count INT CHECK (sales_count >= 0) DEFAULT NULL 78 | ); 79 | 80 | CREATE TABLE IF NOT EXISTS movies ( 81 | movie_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 82 | genre VARCHAR(255) DEFAULT NULL, 83 | rating DECIMAL(2, 1) DEFAULT NULL 84 | ); 85 | 86 | CREATE TABLE IF NOT EXISTS employee_projects ( 87 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 88 | employee_id INT CHECK (employee_id >= 0) DEFAULT NULL, 89 | project_id INT CHECK (project_id >= 0) DEFAULT NULL 90 | ); 91 | 92 | CREATE TABLE IF NOT EXISTS projects ( 93 | project_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 94 | budget INT CHECK (budget >= 0) DEFAULT NULL 95 | ); 96 | 97 | CREATE TABLE IF NOT EXISTS salaries ( 98 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 99 | employee_id INT CHECK (employee_id >= 0) DEFAULT NULL, 100 | month DATE DEFAULT NULL, 101 | salary INT CHECK (salary >= 0) DEFAULT NULL 102 | ); 103 | 104 | CREATE TABLE IF NOT EXISTS product_prices ( 105 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 106 | product_id INT CHECK (product_id >= 0) DEFAULT NULL, 107 | date DATE DEFAULT NULL, 108 | price INT CHECK (price >= 0) DEFAULT NULL 109 | ); 110 | 111 | CREATE TABLE IF NOT EXISTS order_statuses ( 112 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 113 | order_id INT CHECK (order_id >= 0) DEFAULT NULL, 114 | status VARCHAR(255) DEFAULT NULL, 115 | status_date DATE DEFAULT NULL 116 | ); 117 | 118 | CREATE TABLE IF NOT EXISTS project_stages( 119 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 120 | project_id INT CHECK (project_id >= 0) DEFAULT NULL, 121 | stage VARCHAR(255) DEFAULT NULL, 122 | start_date DATE DEFAULT NULL 123 | ); 124 | 125 | CREATE TABLE IF NOT EXISTS daily_sales( 126 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 127 | date DATE DEFAULT NULL, 128 | sales INT CHECK (sales >= 0) DEFAULT NULL 129 | ); 130 | 131 | CREATE TABLE IF NOT EXISTS user_visits( 132 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 133 | user_id INT CHECK (user_id >= 0) DEFAULT NULL, 134 | visit_date DATE DEFAULT NULL, 135 | visit_count INT CHECK (visit_count >= 0) DEFAULT NULL 136 | ); 137 | 138 | CREATE TABLE IF NOT EXISTS monthly_sales( 139 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 140 | region VARCHAR(255) DEFAULT NULL, 141 | month DATE DEFAULT NULL, 142 | sales INT CHECK(sales >= 0) DEFAULT NULL 143 | ); 144 | 145 | CREATE TABLE IF NOT EXISTS customer_orders( 146 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 147 | customer_id INT CHECK(customer_id >= 0) DEFAULT NULL, 148 | order_date DATE DEFAULT NULL, 149 | order_amount INT CHECK(order_amount >= 0) DEFAULT NULL 150 | ); 151 | 152 | CREATE TABLE IF NOT EXISTS product_revenue( 153 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 154 | product_id INT CHECK (product_id >= 0), 155 | revenue_date DATE, 156 | revenue_amount INT CHECK (revenue_amount >= 0) 157 | ); 158 | 159 | CREATE TABLE IF NOT EXISTS student_scores( 160 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 161 | student_id INT CHECK (student_id >= 0), 162 | subject VARCHAR(255), 163 | score INT CHECK ( 164 | score >= 0 165 | AND score <= 100 166 | ) 167 | ); 168 | 169 | CREATE TABLE IF NOT EXISTS employee_sales( 170 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 171 | employee_id INT CHECK (employee_id >= 0), 172 | sales_month DATE, 173 | sales_amount INT CHECK(sales_amount >= 0) 174 | ); 175 | 176 | CREATE TABLE IF NOT EXISTS employee_performance( 177 | id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 178 | employee_id INT CHECK (employee_id >= 0), 179 | tasks_completed INT CHECK (tasks_completed >= 0) 180 | ); 181 | 182 | CREATE TABLE IF NOT EXISTS authors( 183 | author_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 184 | author_name VARCHAR(255) 185 | ); 186 | 187 | CREATE TABLE IF NOT EXISTS books ( 188 | book_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 189 | book_title VARCHAR(255), 190 | author_id INT REFERENCES authors(author_id) ON DELETE CASCADE ON UPDATE CASCADE 191 | ); 192 | 193 | CREATE TABLE IF NOT EXISTS students( 194 | student_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 195 | student_name VARCHAR(255) 196 | ); 197 | 198 | CREATE TABLE IF NOT EXISTS courses( 199 | course_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 200 | course_name VARCHAR(255), 201 | student_id INT REFERENCES students(student_id) ON UPDATE CASCADE ON DELETE CASCADE 202 | ); 203 | 204 | CREATE TABLE IF NOT EXISTS purchases( 205 | purchase_id INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, 206 | client_id INT CHECK (purchase_amount >= 0), 207 | category_id VARCHAR(255), 208 | purchase_amount INT CHECK (purchase_amount >= 0) 209 | ); 210 | 211 | END; -------------------------------------------------------------------------------- /sql/delete-schema.sql: -------------------------------------------------------------------------------- 1 | DO $$ 2 | DECLARE 3 | r RECORD; 4 | BEGIN 5 | -- Выполняем запрос для каждой таблицы в схеме public 6 | FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = 'public') LOOP 7 | EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE'; 8 | END LOOP; 9 | END $$; -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import { readFileSync } from 'fs'; 3 | import { load } from 'js-yaml'; 4 | 5 | function Field() { 6 | return function (target: any, propertyKey: string) { 7 | const fields = Reflect.getMetadata('fields', target) || []; 8 | fields.push(propertyKey); 9 | Reflect.defineMetadata('fields', fields, target); 10 | }; 11 | } 12 | 13 | export class TablesConfig { 14 | 15 | @Field() users: number; 16 | @Field() sales: number; 17 | @Field() employees: number; 18 | @Field() departments: number; 19 | @Field() teams: number; 20 | @Field() orders: number; 21 | @Field() customers: number; 22 | @Field() books: number; 23 | @Field() authors: number; 24 | @Field() courses: number; 25 | @Field() students: number; 26 | @Field() transactions: number; 27 | @Field() student_grades: number; 28 | @Field() student_scores: number; 29 | @Field() responses: number; 30 | @Field() sales_reps: number; 31 | @Field() movies: number; 32 | @Field() purchases: number; 33 | @Field() products: number; 34 | @Field() projects: number; 35 | @Field() salaries: number; 36 | @Field() product_prices: number; 37 | @Field() order_statuses: number; 38 | @Field() project_stages: number; 39 | @Field() daily_sales: number; 40 | @Field() user_visits: number; 41 | @Field() monthly_sales: number; 42 | @Field() customer_orders: number; 43 | @Field() product_revenue: number; 44 | @Field() employee_sales: number; 45 | @Field() employee_projects: number; 46 | @Field() employee_performance: number; 47 | 48 | static [Symbol.hasInstance](instance: any): boolean { 49 | const fields = Reflect.getMetadata('fields', TablesConfig.prototype) || []; 50 | return fields.every( 51 | (field: string) => Object.hasOwn(instance, field) 52 | && Number.isInteger(instance[field]) 53 | && instance[field] >= 0 54 | ); 55 | } 56 | 57 | static getConfig(): TablesConfig { 58 | const config = load(readFileSync('config.yaml', 'utf8')) as TablesConfig; 59 | if(config instanceof TablesConfig){ 60 | return config; 61 | } 62 | throw new Error(`config is not correct!`) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/generator.ts: -------------------------------------------------------------------------------- 1 | import { Presets, SingleBar } from "cli-progress"; 2 | import { DataSource, Repository } from "typeorm"; 3 | import { Departments } from "./pg_schema/entities/Departments"; 4 | import { faker } from "@faker-js/faker"; 5 | import { Teams } from "./pg_schema/entities/Teams"; 6 | import { Employees } from "./pg_schema/entities/Employees"; 7 | import { Customers } from "./pg_schema/entities/Customers"; 8 | import { Orders } from "./pg_schema/entities/Orders"; 9 | import { Transactions } from "./pg_schema/entities/Transactions"; 10 | import { StudentGrades } from "./pg_schema/entities/StudentGrades"; 11 | import { Responses } from "./pg_schema/entities/Responses"; 12 | import { SalesReps } from "./pg_schema/entities/SalesReps"; 13 | import { Movies } from "./pg_schema/entities/Movies"; 14 | import { Purchases } from "./pg_schema/entities/Purchases"; 15 | import { Products } from "./pg_schema/entities/Products"; 16 | import { Projects } from "./pg_schema/entities/Projects"; 17 | import { Salaries } from "./pg_schema/entities/Salaries"; 18 | import { ProductPrices } from "./pg_schema/entities/ProductPrices"; 19 | import { OrderStatuses } from "./pg_schema/entities/OrderStatuses"; 20 | import { ProjectStages } from "./pg_schema/entities/ProjectStages"; 21 | import { DailySales } from "./pg_schema/entities/DailySales"; 22 | import { UserVisits } from "./pg_schema/entities/UserVisits"; 23 | import { MonthlySales } from "./pg_schema/entities/MonthlySales"; 24 | import { CustomerOrders } from "./pg_schema/entities/CustomerOrders"; 25 | import { ProductRevenue } from "./pg_schema/entities/ProductRevenue"; 26 | import { EmployeeSales } from "./pg_schema/entities/EmployeeSales"; 27 | import { EmployeePerformance } from "./pg_schema/entities/EmployeePerformance"; 28 | import { Authors } from "./pg_schema/entities/Authors"; 29 | import { Books } from "./pg_schema/entities/Books"; 30 | import { Students } from "./pg_schema/entities/Students"; 31 | import { Courses } from "./pg_schema/entities/Courses"; 32 | import { readFileSync } from 'fs'; 33 | import { join } from 'path'; 34 | import { TablesConfig } from "./config"; 35 | import { Users } from "./pg_schema/entities/Users"; 36 | import { EmployeeProjects } from "./pg_schema/entities/EmployeeProjects"; 37 | import { Sales } from "./pg_schema/entities/Sales"; 38 | import { StudentScores } from "./pg_schema/entities/StudentScores"; 39 | 40 | type DeepStructure = T | (T extends Array ? DeepStructure[] 41 | : T extends Map ? Map, DeepStructure> 42 | : T extends Set ? Set> : T extends object ? { 43 | [K in keyof T]?: DeepStructure; 44 | } : T); 45 | 46 | 47 | type DeepCallbacks = { 48 | [K in keyof Omit]?: (...args: any[]) => DeepStructure; 49 | } 50 | 51 | 52 | function CreateTableMethod() { 53 | return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) { 54 | const tableMethods = Reflect.getMetadata('tableMethods', target) || []; 55 | const originalMethod = descriptor.value; 56 | 57 | descriptor.value = function (target, ...args: any[]) { 58 | return originalMethod.apply(target, args); 59 | }; 60 | 61 | tableMethods.push(descriptor.value); 62 | Reflect.defineMetadata('tableMethods', tableMethods, target); 63 | return descriptor; 64 | } 65 | } 66 | 67 | 68 | export class Generator { 69 | private readonly dataSource = new DataSource({ 70 | type: 'postgres', 71 | host: 'localhost', 72 | port: Number(process.env.POSTGRES_PORT), 73 | username: process.env.POSTGRES_USER, 74 | password: process.env.POSTGRES_PASSWORD, 75 | database: process.env.POSTGRES_DB, 76 | entities: [__dirname + '/pg_schema/entities/*{.ts,.js}'], 77 | logging: false, 78 | }); 79 | private readonly config = TablesConfig.getConfig(); 80 | 81 | constructor( 82 | private readonly minPrimarySize: number = 100, 83 | private readonly minSecondarySize: number = 10, 84 | ) { } 85 | 86 | public async run() { 87 | await this.dataSource.initialize(); 88 | 89 | await this.deleteSchema(); 90 | await this.createSchema(); 91 | 92 | await this.callTableMethods(); 93 | } 94 | 95 | private async deleteSchema(): Promise { 96 | await this.dataSource.query(readFileSync(join('sql/delete-schema.sql'), 'utf-8')); 97 | await this.dataSource.query(`VACUUM FULL`); 98 | } 99 | 100 | private async createSchema(): Promise { 101 | await this.dataSource.query(readFileSync(join('sql/create-schema.sql'), 'utf-8')); 102 | } 103 | 104 | private async callTableMethods(){ 105 | const methods: Array<(...args: any[]) => Promise> = Reflect 106 | .getMetadata('tableMethods', Generator.prototype) || []; 107 | const uploadingBar = new SingleBar({ 108 | format: `progress |{bar}| {percentage}% | tables created {value}/{total}`, 109 | }, Presets.legacy); 110 | uploadingBar.start(methods.length, 0); 111 | for(const method of methods){ 112 | await method(this); 113 | uploadingBar.increment(); 114 | } 115 | uploadingBar.stop(); 116 | } 117 | 118 | @CreateTableMethod() 119 | private async createEmployeesDepartmentsTeams( 120 | employeesSize: number = this.config.employees || this.minPrimarySize, 121 | departmentsSize: number = this.config.departments || this.minSecondarySize, 122 | teamsSize: number = this.config.teams || this.minSecondarySize, 123 | ): Promise { 124 | const departments = await this.createEntity(Departments)(teamsSize)({ 125 | departmentName: () => faker.person.jobType(), 126 | }); 127 | const teams = await this.createEntity(Teams)(departmentsSize)({ 128 | teamName: () => faker.person.jobArea() 129 | }); 130 | return this.createEntity(Employees)(employeesSize)({ 131 | department_2: () => faker.helpers.arrayElement(departments), 132 | department: () => faker.person.jobType(), 133 | salary: () => faker.number.int({ min: 1500, max: 10000, multipleOf: 50 }), 134 | name: () => faker.person.firstName(), 135 | team: () => faker.helpers.arrayElement(teams) 136 | }); 137 | } 138 | 139 | @CreateTableMethod() 140 | private async createOrdersAndCustomers( 141 | ordersSize: number = this.config.orders || this.minPrimarySize, 142 | customersSize: number = this.config.customers || this.minSecondarySize 143 | ): Promise { 144 | const customers = await this.createEntity(Customers)(customersSize)({ 145 | customerName: () => faker.person.fullName(), 146 | }); 147 | return this.createEntity(Orders)(ordersSize)({ 148 | amount: () => faker.number.int({ min: 0, max: 300, multipleOf: 10 }), 149 | customer: () => faker.helpers.arrayElement(customers), 150 | orderDate: () => faker.date.between({ 151 | from: '2020-01-01T00:00:00.000Z', 152 | to: '2023-01-01T00:00:00.000Z' 153 | }), 154 | }); 155 | } 156 | 157 | @CreateTableMethod() 158 | private async createBooksAndAuthors( 159 | booksSize: number = this.config.books || this.minPrimarySize, 160 | authorsSize: number = this.config.authors || this.minSecondarySize 161 | ): Promise { 162 | const authors = await this.createEntity(Authors)(authorsSize)({ 163 | authorName: () => faker.person.firstName(), 164 | }); 165 | return this.createEntity(Books)(booksSize)({ 166 | author: () => faker.helpers.arrayElement(authors), 167 | bookTitle: () => faker.hacker.phrase() 168 | }); 169 | } 170 | 171 | @CreateTableMethod() 172 | private async createCoursesAndStudents( 173 | coursesSize: number = this.config.courses || this.minPrimarySize, 174 | studentsSize: number = this.config.students || this.minSecondarySize 175 | ): Promise { 176 | const students = await this.createEntity(Students)(studentsSize)({ 177 | studentName: () => faker.person.firstName(), 178 | }); 179 | return this.createEntity(Courses)(coursesSize)({ 180 | student: () => faker.helpers.arrayElement([...students, null]), 181 | courseName: () => faker.lorem.sentence(4) 182 | }); 183 | } 184 | 185 | @CreateTableMethod() 186 | private async createTransactions( 187 | size: number = this.config.transactions || this.minPrimarySize 188 | ): Promise { 189 | return this.createEntity(Transactions)(size)({ 190 | clientId: () => faker.number.int({ min: 0, max: 10 }), 191 | transactionDate: () => faker.date.between({ 192 | from: '2020-01-01T00:00:00.000Z', 193 | to: '2023-01-01T00:00:00.000Z' 194 | }), 195 | }); 196 | } 197 | 198 | @CreateTableMethod() 199 | private async createStudentGrades( 200 | size: number = this.config.student_grades || this.minPrimarySize 201 | ): Promise { 202 | return this.createEntity(StudentGrades)(size)({ 203 | studentId: () => faker.number.int({ min: 0, max: 50 }), 204 | courseId: () => faker.number.int({ min: 0, max: 10 }), 205 | grade: () => faker.number.int({ min: 0, max: 100 }), 206 | }); 207 | } 208 | 209 | @CreateTableMethod() 210 | private async createResponses( 211 | size: number = this.config.responses || this.minPrimarySize 212 | ): Promise { 213 | return this.createEntity(Responses)(size)({ 214 | employeeId: () => faker.number.int({ min: 0, max: 50 }), 215 | responseTime: () => faker.number.int({ min: 0, max: 100, multipleOf: 10 }), 216 | }); 217 | } 218 | 219 | @CreateTableMethod() 220 | private async createSalesReps( 221 | size: number = this.config.sales_reps || this.minPrimarySize 222 | ): Promise { 223 | return this.createEntity(SalesReps)(size)({ 224 | salesCount: () => faker.number.int({ min: 0, max: 1000 }), 225 | month: () => faker.date.between({ 226 | from: '2020-01-01T00:00:00.000Z', 227 | to: '2020-06-01T00:00:00.000Z' 228 | }).toDateString() 229 | }); 230 | } 231 | 232 | @CreateTableMethod() 233 | private async createMovies( 234 | size: number = this.config.movies || this.minPrimarySize 235 | ): Promise { 236 | return this.createEntity(Movies)(size)({ 237 | genre: () => faker.music.genre(), 238 | rating: () => faker.number.float({ min: 0, max: 9.9, fractionDigits: 1 }).toFixed(1) 239 | }); 240 | } 241 | 242 | @CreateTableMethod() 243 | private async createPurchases( 244 | size: number = this.config.purchases || this.minPrimarySize 245 | ): Promise { 246 | return this.createEntity(Purchases)(size)({ 247 | clientId: () => faker.number.int({ min: 0, max: 10 }), 248 | categoryId: () => faker.helpers.arrayElement(['A', 'B', 'C', 'D', 'E']), 249 | purchaseAmount: () => faker.number.int({ min: 0, max: 1000 }) 250 | }); 251 | } 252 | 253 | @CreateTableMethod() 254 | private async createProducts( 255 | size: number = this.config.products || this.minPrimarySize 256 | ): Promise { 257 | return this.createEntity(Products)(size)({ 258 | productId: () => faker.number.int({ min: 0, max: 50 }), 259 | sales: () => faker.number.int({ min: 0, max: 5000, multipleOf: 100 }) 260 | }); 261 | } 262 | 263 | @CreateTableMethod() 264 | private async createProjects( 265 | size: number = this.config.projects || this.minPrimarySize 266 | ): Promise { 267 | return this.createEntity(Projects)(size)({ 268 | budget: () => faker.number.int({ min: 0, max: 100_000, multipleOf: 1000 }) 269 | }); 270 | } 271 | 272 | @CreateTableMethod() 273 | private async createSalaries( 274 | size: number = this.config.salaries || this.minPrimarySize 275 | ): Promise { 276 | return this.createEntity(Salaries)(size)({ 277 | employeeId: () => faker.number.int({ min: 0, max: 5 }), 278 | salary: () => faker.number.int({ min: 2000, max: 10000, multipleOf: 100 }), 279 | month: () => faker.date.between({ 280 | from: '2020-01-01T00:00:00.000Z', 281 | to: '2020-06-01T00:00:00.000Z' 282 | }).toDateString() 283 | }); 284 | } 285 | 286 | @CreateTableMethod() 287 | private async createProductPrices( 288 | size: number = this.config.product_prices || this.minPrimarySize 289 | ): Promise { 290 | return this.createEntity(ProductPrices)(size)({ 291 | productId: () => faker.number.int({ min: 0, max: 10 }), 292 | price: () => faker.number.int({ min: 0, max: 500, multipleOf: 10 }), 293 | date: () => faker.date.between({ 294 | from: '2020-01-01T00:00:00.000Z', 295 | to: '2020-06-01T00:00:00.000Z' 296 | }).toDateString(), 297 | }); 298 | } 299 | 300 | @CreateTableMethod() 301 | private async createOrderStatuses( 302 | size: number = this.config.order_statuses || this.minPrimarySize 303 | ): Promise { 304 | return this.createEntity(OrderStatuses)(size)({ 305 | status: () => faker.helpers.arrayElement(['Shipped', 'Delivered', 'Pending']), 306 | orderId: () => faker.number.int({ min: 0, max: 10 }), 307 | statusDate: () => faker.date.between({ 308 | from: '2020-01-01T00:00:00.000Z', 309 | to: '2020-06-01T00:00:00.000Z' 310 | }).toDateString(), 311 | }); 312 | } 313 | 314 | @CreateTableMethod() 315 | private async createProjectStages( 316 | size: number = this.config.project_stages || this.minPrimarySize 317 | ): Promise { 318 | return this.createEntity(ProjectStages)(size)({ 319 | projectId: () => faker.number.int({ min: 0, max: 5 }), 320 | stage: () => faker.helpers.arrayElement(['Planning', 'Execution', 'Review']), 321 | startDate: () => faker.date.between({ 322 | from: '2020-01-01T00:00:00.000Z', 323 | to: '2020-06-01T00:00:00.000Z' 324 | }).toDateString(), 325 | }); 326 | } 327 | 328 | @CreateTableMethod() 329 | private async createDailySales( 330 | size: number = this.config.daily_sales || this.minPrimarySize 331 | ): Promise { 332 | return this.createEntity(DailySales)(size)({ 333 | sales: () => faker.number.int({ min: 0, max: 500, multipleOf: 10 }), 334 | date: () => faker.date.between({ 335 | from: '2020-01-01T00:00:00.000Z', 336 | to: '2020-06-01T00:00:00.000Z' 337 | }).toDateString(), 338 | }); 339 | } 340 | 341 | @CreateTableMethod() 342 | private async createUserVisits( 343 | size: number = this.config.user_visits || this.minPrimarySize 344 | ): Promise { 345 | return this.createEntity(UserVisits)(size)({ 346 | userId: () => faker.number.int({ min: 0, max: 5 }), 347 | visitCount: () => faker.number.int({ min: 0, max: 10 }), 348 | visitDate: () => faker.date.between({ 349 | from: '2020-01-01T00:00:00.000Z', 350 | to: '2020-06-01T00:00:00.000Z' 351 | }).toDateString(), 352 | }); 353 | } 354 | 355 | @CreateTableMethod() 356 | private async createMonthlySales( 357 | size: number = this.config.monthly_sales || this.minPrimarySize 358 | ): Promise { 359 | return this.createEntity(MonthlySales)(size)({ 360 | region: () => faker.helpers.arrayElement(['North', 'South ', 'West', 'East']), 361 | sales: () => faker.number.int({ min: 0, max: 2000, multipleOf: 10 }), 362 | month: () => faker.date.between({ 363 | from: '2020-01-01T00:00:00.000Z', 364 | to: '2020-06-01T00:00:00.000Z' 365 | }).toDateString(), 366 | }); 367 | } 368 | 369 | @CreateTableMethod() 370 | private async createCustomerOrders( 371 | size: number = this.config.customer_orders || this.minPrimarySize 372 | ): Promise { 373 | return this.createEntity(CustomerOrders)(size)({ 374 | customerId: () => faker.number.int({ min: 0, max: 10 }), 375 | orderAmount: () => faker.number.int({ min: 0, max: 500, multipleOf: 10 }), 376 | orderDate: () => faker.date.between({ 377 | from: '2020-01-01T00:00:00.000Z', 378 | to: '2020-06-01T00:00:00.000Z' 379 | }).toDateString(), 380 | }); 381 | } 382 | 383 | @CreateTableMethod() 384 | private async createProductRevenue( 385 | size: number = this.config.product_revenue || this.minPrimarySize 386 | ): Promise { 387 | return this.createEntity(ProductRevenue)(size)({ 388 | productId: () => faker.number.int({ min: 0, max: 10 }), 389 | revenueAmount: () => faker.number.int({ min: 100, max: 800, multipleOf: 100 }), 390 | revenueDate: () => faker.date.between({ 391 | from: '2020-01-01T00:00:00.000Z', 392 | to: '2020-06-01T00:00:00.000Z' 393 | }).toDateString(), 394 | }); 395 | } 396 | 397 | @CreateTableMethod() 398 | private async createEmployeeSales( 399 | size: number = this.config.employee_sales || this.minPrimarySize 400 | ): Promise { 401 | return this.createEntity(EmployeeSales)(size)({ 402 | employeeId: () => faker.number.int({ min: 0, max: 10 }), 403 | salesAmount: () => faker.number.int({ min: 2000, max: 8000, multipleOf: 100 }), 404 | salesMonth: () => faker.date.between({ 405 | from: '2020-01-01T00:00:00.000Z', 406 | to: '2020-01-01T00:00:00.000Z' 407 | }).toDateString(), 408 | }); 409 | } 410 | 411 | @CreateTableMethod() 412 | private async createEmployeePerformance( 413 | size: number = this.config.employee_performance || this.minPrimarySize 414 | ): Promise { 415 | return this.createEntity(EmployeePerformance)(size)({ 416 | employeeId: () => faker.number.int({ min: 0, max: 10 }), 417 | tasksCompleted: () => faker.number.int({ min: 10, max: 20 }), 418 | }); 419 | } 420 | 421 | @CreateTableMethod() 422 | private async createUsers( 423 | size: number = this.config.users || this.minPrimarySize, 424 | ): Promise { 425 | return this.createEntity(Users)(size)({ 426 | username: () => faker.person.fullName(), 427 | email: () => faker.internet.email(), 428 | password: () => faker.string.hexadecimal({length:{min: 30, max: 30}}) 429 | }); 430 | } 431 | 432 | @CreateTableMethod() 433 | private async createEmployeeProjects( 434 | size: number = this.config.employee_projects || this.minPrimarySize, 435 | ): Promise { 436 | return this.createEntity(EmployeeProjects)(size)({ 437 | employeeId: () => faker.number.int({ min: 0, max: 10 }), 438 | projectId: () => faker.number.int({ min: 0, max: 10 }), 439 | }); 440 | } 441 | 442 | @CreateTableMethod() 443 | private async createSales( 444 | size: number = this.config.sales || this.minPrimarySize, 445 | ): Promise { 446 | return this.createEntity(Sales)(size)({ 447 | productId: () => faker.number.int({ min: 0, max: 10 }), 448 | amount: () => faker.number.int({ min: 1000, max: 8000, multipleOf: 100 }), 449 | saleDate: () => faker.date.between({ 450 | from: '2020-01-01T00:00:00.000Z', 451 | to: '2024-01-01T00:00:00.000Z' 452 | }).toDateString(), 453 | }); 454 | } 455 | 456 | @CreateTableMethod() 457 | private async createStudentScores( 458 | size: number = this.config.student_scores || this.minPrimarySize, 459 | ): Promise { 460 | return this.createEntity(StudentScores)(size)({ 461 | studentId: () => faker.number.int({ min: 0, max: size }), 462 | score: () => faker.number.int({ min: 0, max: 100 }), 463 | subject: () => faker.helpers.arrayElement(['Math', 'Physics', 'History']), 464 | }); 465 | } 466 | 467 | private createEntity(targetEntity: new () => Entity) { 468 | return (length: number) => { 469 | return async (entityCallbacks: DeepCallbacks) => { 470 | const limit = 1000; 471 | const repository = this.dataSource.getRepository(targetEntity); 472 | const raws = new Array(Math.ceil(length / limit)).fill(null).map( 473 | (_, index) => new Array( 474 | (length / (index + 1)) > limit ? limit : length - (limit * index) 475 | ) 476 | ); 477 | for (let i = 0; i < raws.length; i++) { 478 | for (let j = 0; j < raws[i].length; j++) { 479 | let obj: Partial = {}; 480 | for (const key in entityCallbacks) { 481 | if (typeof entityCallbacks[key] === 'function') { 482 | obj[key as keyof Entity] = entityCallbacks[key](); 483 | } 484 | } 485 | const raw = repository.create(obj as Entity); 486 | raws[i][j] = raw; 487 | } 488 | } 489 | const results = await Promise.all( 490 | raws.map(async (raw) => repository.save(raw)) 491 | ); 492 | return results.flat(); 493 | } 494 | } 495 | } 496 | } -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { Generator } from './generator'; 2 | 3 | (async () => { 4 | const gen = new Generator(100, 10); 5 | await gen.run(); 6 | })(); -------------------------------------------------------------------------------- /src/pg_schema/entities/Authors.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | Index, 5 | OneToMany, 6 | PrimaryGeneratedColumn, 7 | } from "typeorm"; 8 | import { Books } from "./Books"; 9 | 10 | @Index("authors_pkey", ["authorId"], { unique: true }) 11 | @Entity("authors", { schema: "public" }) 12 | export class Authors { 13 | @PrimaryGeneratedColumn({ type: "integer", name: "author_id" }) 14 | authorId: number; 15 | 16 | @Column("character varying", { 17 | name: "author_name", 18 | nullable: true, 19 | length: 255, 20 | }) 21 | authorName: string | null; 22 | 23 | @OneToMany(() => Books, (books) => books.author) 24 | books: Books[]; 25 | } 26 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Books.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | Index, 5 | JoinColumn, 6 | ManyToOne, 7 | PrimaryGeneratedColumn, 8 | } from "typeorm"; 9 | import { Authors } from "./Authors"; 10 | 11 | @Index("books_pkey", ["bookId"], { unique: true }) 12 | @Entity("books", { schema: "public" }) 13 | export class Books { 14 | @PrimaryGeneratedColumn({ type: "integer", name: "book_id" }) 15 | bookId: number; 16 | 17 | @Column("character varying", { 18 | name: "book_title", 19 | nullable: true, 20 | length: 255, 21 | }) 22 | bookTitle: string | null; 23 | 24 | @ManyToOne(() => Authors, (authors) => authors.books, { 25 | onDelete: "CASCADE", 26 | onUpdate: "CASCADE", 27 | }) 28 | @JoinColumn([{ name: "author_id", referencedColumnName: "authorId" }]) 29 | author: Authors; 30 | } 31 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Courses.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | Index, 5 | JoinColumn, 6 | ManyToOne, 7 | PrimaryGeneratedColumn, 8 | } from "typeorm"; 9 | import { Students } from "./Students"; 10 | 11 | @Index("courses_pkey", ["courseId"], { unique: true }) 12 | @Entity("courses", { schema: "public" }) 13 | export class Courses { 14 | @PrimaryGeneratedColumn({ type: "integer", name: "course_id" }) 15 | courseId: number; 16 | 17 | @Column("character varying", { 18 | name: "course_name", 19 | nullable: true, 20 | length: 255, 21 | }) 22 | courseName: string | null; 23 | 24 | @ManyToOne(() => Students, (students) => students.courses, { 25 | onDelete: "CASCADE", 26 | onUpdate: "CASCADE", 27 | }) 28 | @JoinColumn([{ name: "student_id", referencedColumnName: "studentId" }]) 29 | student: Students; 30 | } 31 | -------------------------------------------------------------------------------- /src/pg_schema/entities/CustomerOrders.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("customer_orders_pkey", ["id"], { unique: true }) 4 | @Entity("customer_orders", { schema: "public" }) 5 | export class CustomerOrders { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "customer_id", nullable: true }) 10 | customerId: number | null; 11 | 12 | @Column("date", { name: "order_date", nullable: true }) 13 | orderDate: string | null; 14 | 15 | @Column("integer", { name: "order_amount", nullable: true }) 16 | orderAmount: number | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Customers.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | Index, 5 | OneToMany, 6 | PrimaryGeneratedColumn, 7 | } from "typeorm"; 8 | import { Orders } from "./Orders"; 9 | 10 | @Index("customers_pkey", ["customerId"], { unique: true }) 11 | @Entity("customers", { schema: "public" }) 12 | export class Customers { 13 | @PrimaryGeneratedColumn({ type: "integer", name: "customer_id" }) 14 | customerId: number; 15 | 16 | @Column("character varying", { 17 | name: "customer_name", 18 | nullable: true, 19 | length: 255, 20 | }) 21 | customerName: string | null; 22 | 23 | @OneToMany(() => Orders, (orders) => orders.customer) 24 | orders: Orders[]; 25 | } 26 | -------------------------------------------------------------------------------- /src/pg_schema/entities/DailySales.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("daily_sales_pkey", ["id"], { unique: true }) 4 | @Entity("daily_sales", { schema: "public" }) 5 | export class DailySales { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("date", { name: "date", nullable: true }) 10 | date: string | null; 11 | 12 | @Column("integer", { name: "sales", nullable: true }) 13 | sales: number | null; 14 | } 15 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Departments.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | Index, 5 | OneToMany, 6 | PrimaryGeneratedColumn, 7 | } from "typeorm"; 8 | import { Employees } from "./Employees"; 9 | 10 | @Index("departments_pkey", ["departmentId"], { unique: true }) 11 | @Entity("departments", { schema: "public" }) 12 | export class Departments { 13 | @PrimaryGeneratedColumn({ type: "integer", name: "department_id" }) 14 | departmentId: number; 15 | 16 | @Column("character varying", { 17 | name: "department_name", 18 | nullable: true, 19 | length: 255, 20 | }) 21 | departmentName: string | null; 22 | 23 | @OneToMany(() => Employees, (employees) => employees.department_2) 24 | employees: Employees[]; 25 | } 26 | -------------------------------------------------------------------------------- /src/pg_schema/entities/EmployeePerformance.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("employee_performance_pkey", ["id"], { unique: true }) 4 | @Entity("employee_performance", { schema: "public" }) 5 | export class EmployeePerformance { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "employee_id", nullable: true }) 10 | employeeId: number | null; 11 | 12 | @Column("integer", { name: "tasks_completed", nullable: true }) 13 | tasksCompleted: number | null; 14 | } 15 | -------------------------------------------------------------------------------- /src/pg_schema/entities/EmployeeProjects.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("employee_projects_pkey", ["id"], { unique: true }) 4 | @Entity("employee_projects", { schema: "public" }) 5 | export class EmployeeProjects { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "employee_id", nullable: true }) 10 | employeeId: number | null; 11 | 12 | @Column("integer", { name: "project_id", nullable: true }) 13 | projectId: number | null; 14 | } 15 | -------------------------------------------------------------------------------- /src/pg_schema/entities/EmployeeSales.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("employee_sales_pkey", ["id"], { unique: true }) 4 | @Entity("employee_sales", { schema: "public" }) 5 | export class EmployeeSales { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "employee_id", nullable: true }) 10 | employeeId: number | null; 11 | 12 | @Column("date", { name: "sales_month", nullable: true }) 13 | salesMonth: string | null; 14 | 15 | @Column("integer", { name: "sales_amount", nullable: true }) 16 | salesAmount: number | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Employees.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | Index, 5 | JoinColumn, 6 | ManyToOne, 7 | PrimaryGeneratedColumn, 8 | } from "typeorm"; 9 | import { Departments } from "./Departments"; 10 | import { Teams } from "./Teams"; 11 | 12 | @Index("employees_pkey", ["employeeId"], { unique: true }) 13 | @Entity("employees", { schema: "public" }) 14 | export class Employees { 15 | @PrimaryGeneratedColumn({ type: "integer", name: "employee_id" }) 16 | employeeId: number; 17 | 18 | @Column("character varying", { 19 | name: "name", 20 | nullable: true, 21 | length: 255, 22 | default: () => "NULL::character varying", 23 | }) 24 | name: string | null; 25 | 26 | @Column("character varying", { 27 | name: "department", 28 | nullable: true, 29 | length: 255, 30 | default: () => "NULL::character varying", 31 | }) 32 | department: string | null; 33 | 34 | @Column("integer", { name: "salary", nullable: true }) 35 | salary: number | null; 36 | 37 | @ManyToOne(() => Departments, (departments) => departments.employees, { 38 | onDelete: "CASCADE", 39 | onUpdate: "CASCADE", 40 | }) 41 | @JoinColumn([{ name: "department_id", referencedColumnName: "departmentId" }]) 42 | department_2: Departments; 43 | 44 | @ManyToOne(() => Teams, (teams) => teams.employees, { 45 | onDelete: "CASCADE", 46 | onUpdate: "CASCADE", 47 | }) 48 | @JoinColumn([{ name: "team_id", referencedColumnName: "teamId" }]) 49 | team: Teams; 50 | } 51 | -------------------------------------------------------------------------------- /src/pg_schema/entities/MonthlySales.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("monthly_sales_pkey", ["id"], { unique: true }) 4 | @Entity("monthly_sales", { schema: "public" }) 5 | export class MonthlySales { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("character varying", { 10 | name: "region", 11 | nullable: true, 12 | length: 255, 13 | default: () => "NULL::character varying", 14 | }) 15 | region: string | null; 16 | 17 | @Column("date", { name: "month", nullable: true }) 18 | month: string | null; 19 | 20 | @Column("integer", { name: "sales", nullable: true }) 21 | sales: number | null; 22 | } 23 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Movies.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("movies_pkey", ["movieId"], { unique: true }) 4 | @Entity("movies", { schema: "public" }) 5 | export class Movies { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "movie_id" }) 7 | movieId: number; 8 | 9 | @Column("character varying", { 10 | name: "genre", 11 | nullable: true, 12 | length: 255, 13 | default: () => "NULL::character varying", 14 | }) 15 | genre: string | null; 16 | 17 | @Column("numeric", { 18 | name: "rating", 19 | nullable: true, 20 | precision: 2, 21 | scale: 1, 22 | default: () => "NULL::numeric", 23 | }) 24 | rating: string | null; 25 | } 26 | -------------------------------------------------------------------------------- /src/pg_schema/entities/OrderStatuses.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("order_statuses_pkey", ["id"], { unique: true }) 4 | @Entity("order_statuses", { schema: "public" }) 5 | export class OrderStatuses { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "order_id", nullable: true }) 10 | orderId: number | null; 11 | 12 | @Column("character varying", { 13 | name: "status", 14 | nullable: true, 15 | length: 255, 16 | default: () => "NULL::character varying", 17 | }) 18 | status: string | null; 19 | 20 | @Column("date", { name: "status_date", nullable: true }) 21 | statusDate: string | null; 22 | } 23 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Orders.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | Index, 5 | JoinColumn, 6 | ManyToOne, 7 | PrimaryGeneratedColumn, 8 | } from "typeorm"; 9 | import { Customers } from "./Customers"; 10 | 11 | @Index("orders_pkey", ["orderId"], { unique: true }) 12 | @Entity("orders", { schema: "public" }) 13 | export class Orders { 14 | @PrimaryGeneratedColumn({ type: "integer", name: "order_id" }) 15 | orderId: number; 16 | 17 | @Column("integer", { name: "amount", nullable: true }) 18 | amount: number | null; 19 | 20 | @Column("timestamp without time zone", { name: "order_date", nullable: true }) 21 | orderDate: Date | null; 22 | 23 | @ManyToOne(() => Customers, (customers) => customers.orders, { 24 | onDelete: "CASCADE", 25 | onUpdate: "CASCADE", 26 | }) 27 | @JoinColumn([{ name: "customer_id", referencedColumnName: "customerId" }]) 28 | customer: Customers; 29 | } 30 | -------------------------------------------------------------------------------- /src/pg_schema/entities/ProductPrices.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("product_prices_pkey", ["id"], { unique: true }) 4 | @Entity("product_prices", { schema: "public" }) 5 | export class ProductPrices { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "product_id", nullable: true }) 10 | productId: number | null; 11 | 12 | @Column("date", { name: "date", nullable: true }) 13 | date: string | null; 14 | 15 | @Column("integer", { name: "price", nullable: true }) 16 | price: number | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/ProductRevenue.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("product_revenue_pkey", ["id"], { unique: true }) 4 | @Entity("product_revenue", { schema: "public" }) 5 | export class ProductRevenue { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "product_id", nullable: true }) 10 | productId: number | null; 11 | 12 | @Column("date", { name: "revenue_date", nullable: true }) 13 | revenueDate: string | null; 14 | 15 | @Column("integer", { name: "revenue_amount", nullable: true }) 16 | revenueAmount: number | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Products.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("products_pkey", ["id"], { unique: true }) 4 | @Entity("products", { schema: "public" }) 5 | export class Products { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "product_id", nullable: true }) 10 | productId: number | null; 11 | 12 | @Column("integer", { name: "sales", nullable: true }) 13 | sales: number | null; 14 | } 15 | -------------------------------------------------------------------------------- /src/pg_schema/entities/ProjectStages.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("project_stages_pkey", ["id"], { unique: true }) 4 | @Entity("project_stages", { schema: "public" }) 5 | export class ProjectStages { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "project_id", nullable: true }) 10 | projectId: number | null; 11 | 12 | @Column("character varying", { 13 | name: "stage", 14 | nullable: true, 15 | length: 255, 16 | default: () => "NULL::character varying", 17 | }) 18 | stage: string | null; 19 | 20 | @Column("date", { name: "start_date", nullable: true }) 21 | startDate: string | null; 22 | } 23 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Projects.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("projects_pkey", ["projectId"], { unique: true }) 4 | @Entity("projects", { schema: "public" }) 5 | export class Projects { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "project_id" }) 7 | projectId: number; 8 | 9 | @Column("integer", { name: "budget", nullable: true }) 10 | budget: number | null; 11 | } 12 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Purchases.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("purchases_pkey", ["purchaseId"], { unique: true }) 4 | @Entity("purchases", { schema: "public" }) 5 | export class Purchases { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "purchase_id" }) 7 | purchaseId: number; 8 | 9 | @Column("integer", { name: "client_id", nullable: true }) 10 | clientId: number | null; 11 | 12 | @Column("character varying", { 13 | name: "category_id", 14 | nullable: true, 15 | length: 255, 16 | }) 17 | categoryId: string | null; 18 | 19 | @Column("integer", { name: "purchase_amount", nullable: true }) 20 | purchaseAmount: number | null; 21 | } 22 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Responses.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("responses_pkey", ["id"], { unique: true }) 4 | @Entity("responses", { schema: "public" }) 5 | export class Responses { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "employee_id", nullable: true }) 10 | employeeId: number | null; 11 | 12 | @Column("integer", { name: "response_time", nullable: true }) 13 | responseTime: number | null; 14 | } 15 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Salaries.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("salaries_pkey", ["id"], { unique: true }) 4 | @Entity("salaries", { schema: "public" }) 5 | export class Salaries { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "employee_id", nullable: true }) 10 | employeeId: number | null; 11 | 12 | @Column("date", { name: "month", nullable: true }) 13 | month: string | null; 14 | 15 | @Column("integer", { name: "salary", nullable: true }) 16 | salary: number | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Sales.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("sales_pkey", ["id"], { unique: true }) 4 | @Entity("sales", { schema: "public" }) 5 | export class Sales { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "product_id", nullable: true }) 10 | productId: number | null; 11 | 12 | @Column("timestamp without time zone", { name: "sale_date", nullable: true }) 13 | saleDate: Date | null; 14 | 15 | @Column("integer", { name: "amount", nullable: true }) 16 | amount: number | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/SalesReps.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("sales_reps_pkey", ["salesRepId"], { unique: true }) 4 | @Entity("sales_reps", { schema: "public" }) 5 | export class SalesReps { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "sales_rep_id" }) 7 | salesRepId: number; 8 | 9 | @Column("date", { name: "month", nullable: true }) 10 | month: string | null; 11 | 12 | @Column("integer", { name: "sales_count", nullable: true }) 13 | salesCount: number | null; 14 | } 15 | -------------------------------------------------------------------------------- /src/pg_schema/entities/StudentGrades.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("student_grades_pkey", ["id"], { unique: true }) 4 | @Entity("student_grades", { schema: "public" }) 5 | export class StudentGrades { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "student_id", nullable: true }) 10 | studentId: number | null; 11 | 12 | @Column("integer", { name: "course_id", nullable: true }) 13 | courseId: number | null; 14 | 15 | @Column("integer", { name: "grade", nullable: true }) 16 | grade: number | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/StudentScores.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("student_scores_pkey", ["id"], { unique: true }) 4 | @Entity("student_scores", { schema: "public" }) 5 | export class StudentScores { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "student_id", nullable: true }) 10 | studentId: number | null; 11 | 12 | @Column("character varying", { name: "subject", nullable: true, length: 255 }) 13 | subject: string | null; 14 | 15 | @Column("integer", { name: "score", nullable: true }) 16 | score: number | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Students.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | Index, 5 | OneToMany, 6 | PrimaryGeneratedColumn, 7 | } from "typeorm"; 8 | import { Courses } from "./Courses"; 9 | 10 | @Index("students_pkey", ["studentId"], { unique: true }) 11 | @Entity("students", { schema: "public" }) 12 | export class Students { 13 | @PrimaryGeneratedColumn({ type: "integer", name: "student_id" }) 14 | studentId: number; 15 | 16 | @Column("character varying", { 17 | name: "student_name", 18 | nullable: true, 19 | length: 255, 20 | }) 21 | studentName: string | null; 22 | 23 | @OneToMany(() => Courses, (courses) => courses.student) 24 | courses: Courses[]; 25 | } 26 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Teams.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Column, 3 | Entity, 4 | Index, 5 | OneToMany, 6 | PrimaryGeneratedColumn, 7 | } from "typeorm"; 8 | import { Employees } from "./Employees"; 9 | 10 | @Index("teams_pkey", ["teamId"], { unique: true }) 11 | @Entity("teams", { schema: "public" }) 12 | export class Teams { 13 | @PrimaryGeneratedColumn({ type: "integer", name: "team_id" }) 14 | teamId: number; 15 | 16 | @Column("character varying", { 17 | name: "team_name", 18 | nullable: true, 19 | length: 255, 20 | default: () => "NULL::character varying", 21 | }) 22 | teamName: string | null; 23 | 24 | @OneToMany(() => Employees, (employees) => employees.team) 25 | employees: Employees[]; 26 | } 27 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Transactions.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("transactions_pkey", ["transactionId"], { unique: true }) 4 | @Entity("transactions", { schema: "public" }) 5 | export class Transactions { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "transaction_id" }) 7 | transactionId: number; 8 | 9 | @Column("integer", { name: "client_id", nullable: true }) 10 | clientId: number | null; 11 | 12 | @Column("timestamp without time zone", { 13 | name: "transaction_date", 14 | nullable: true, 15 | }) 16 | transactionDate: Date | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/UserVisits.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("user_visits_pkey", ["id"], { unique: true }) 4 | @Entity("user_visits", { schema: "public" }) 5 | export class UserVisits { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("integer", { name: "user_id", nullable: true }) 10 | userId: number | null; 11 | 12 | @Column("date", { name: "visit_date", nullable: true }) 13 | visitDate: string | null; 14 | 15 | @Column("integer", { name: "visit_count", nullable: true }) 16 | visitCount: number | null; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/entities/Users.ts: -------------------------------------------------------------------------------- 1 | import { Column, Entity, Index, PrimaryGeneratedColumn } from "typeorm"; 2 | 3 | @Index("users_pkey", ["id"], { unique: true }) 4 | @Entity("users", { schema: "public" }) 5 | export class Users { 6 | @PrimaryGeneratedColumn({ type: "integer", name: "id" }) 7 | id: number; 8 | 9 | @Column("character varying", { name: "username", length: 50 }) 10 | username: string; 11 | 12 | @Column("character varying", { name: "email", length: 100 }) 13 | email: string; 14 | 15 | @Column("character varying", { name: "password", length: 255 }) 16 | password: string; 17 | } 18 | -------------------------------------------------------------------------------- /src/pg_schema/ormconfig.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "default", 4 | "type": "postgres", 5 | "host": "localhost", 6 | "port": 5432, 7 | "username": "user", 8 | "password": "password", 9 | "database": "", 10 | "synchronize": false, 11 | "entities": ["entities/*.js"] 12 | } 13 | ] 14 | -------------------------------------------------------------------------------- /src/pg_schema/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2017", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "sourceMap": true 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/test.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/shkvik/nodejs-dbgen/ba37a26061fca0b5ebf9e4d67648b71531c52cfe/test/test.ts -------------------------------------------------------------------------------- /tsconfig.build.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "exclude": ["node_modules", "dist" ] 4 | } 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "CommonJS", 4 | "declaration": true, 5 | "removeComments": true, 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "allowSyntheticDefaultImports": true, 9 | "target": "ES2023", 10 | "sourceMap": true, 11 | "outDir": "./dist", 12 | "baseUrl": "./", 13 | "incremental": true, 14 | "skipLibCheck": true, 15 | "strictNullChecks": false, 16 | "noImplicitAny": false, 17 | "strictBindCallApply": false, 18 | "forceConsistentCasingInFileNames": false, 19 | "noFallthroughCasesInSwitch": false 20 | }, 21 | "include": ["src", "test"] 22 | } 23 | --------------------------------------------------------------------------------