diff --git a/.sequelizerc b/.sequelizerc new file mode 100644 index 00000000..b2bdbecd --- /dev/null +++ b/.sequelizerc @@ -0,0 +1,8 @@ +const path = require('path'); + +module.exports = { + config: path.resolve('db', 'config.json'), + //'models-path': path.resolve('src/services/db', 'models'), + 'seeders-path': path.resolve('db', 'seeders'), + 'migrations-path': path.resolve('db', 'migrations'), +}; \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index b1bc41ab..df6e1c81 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,10 +41,15 @@ WORKDIR /usr/src/app COPY --from=build /usr/src/app/node_modules ./node_modules COPY --from=build /usr/src/app/server ./server COPY --from=build /usr/src/app/dist ./dist +COPY --from=build /usr/src/app/db ./db +COPY --from=build /usr/src/app/.sequelizerc ./ + # COPY --from=build /usr/src/app/.env ./ # Expose the application port EXPOSE 3000 +VOLUME /usr/src/app/data + # Start the application -CMD [ "node", "server/entry.express" ] +CMD "/bin/bash -c 'node node_modules/sequelize-cli/lib/sequelize db:migrate --env production && node server/entry.express.js'" diff --git a/README.md b/README.md index af4c264a..6fc50c68 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ OAUTH_CLIENT_ID HF_TOKEN=X ``` -Please note that if you define the `HF_TOKEN`, this variable will take priority over `OAUTH_CLIENT_ID`. +Please note that if you define the `OAUTH_CLIENT_ID`, this variable will take priority over `HF_TOKEN`. Development mode uses [Vite's development server](https://vitejs.dev/). The `dev` command will server-side render (SSR) the output during development. @@ -101,3 +101,19 @@ pnpm serve ``` Then visit [http://localhost:8080/](http://localhost:8080/) + +### DB migrations + +Before running a server, the database migrations must be up-to-date. The default `pnpm dev`, `pnpm test`, `pnpm preview`, and `pnpm server` commands already include this step. However, if you want to run migrations manually, you can use the following command: + +``` +pnpm migrate:up +``` + +If you want to rollback all the migrations, you can use the following command: + +``` +pnpm migrate:down +``` + +For more information, visit the official [Sequelize documentation on migrations](https://sequelize.org/docs/v6/other-topics/migrations/#running-migrations). diff --git a/db/config.json b/db/config.json new file mode 100644 index 00000000..d069de1d --- /dev/null +++ b/db/config.json @@ -0,0 +1,25 @@ +{ + "development": { + "username": null, + "password": null, + "database": "dataground", + "dialect": "sqlite", + "storage": "data/development.db" + }, + + "test": { + "username": null, + "password": null, + "database": "dataground", + "dialect": "sqlite", + "storage": "data/test.db" + }, + + "production": { + "username": null, + "password": null, + "database": "dataground", + "dialect": "sqlite", + "storage": "data/production.db" + } +} diff --git a/db/migrations/20250312091036-create-datasets-table.js b/db/migrations/20250312091036-create-datasets-table.js new file mode 100644 index 00000000..2f72cd82 --- /dev/null +++ b/db/migrations/20250312091036-create-datasets-table.js @@ -0,0 +1,30 @@ +module.exports = { + up: async (queryInterface, Sequelize) => { + return await queryInterface.createTable('datasets', { + id: { + type: Sequelize.DataTypes.UUID, + defaultValue: Sequelize.DataTypes.UUIDV4, + primaryKey: true, + }, + name: { + type: Sequelize.DataTypes.STRING, + allowNull: false, + }, + createdBy: { + type: Sequelize.DataTypes.STRING, + allowNull: false, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + }, + }); + }, + down: async (queryInterface, Sequelize) => { + return await queryInterface.dropTable('datasets'); + }, +}; diff --git a/db/migrations/20250312092712-create-columns-table.js b/db/migrations/20250312092712-create-columns-table.js new file mode 100644 index 00000000..49bd9d6f --- /dev/null +++ b/db/migrations/20250312092712-create-columns-table.js @@ -0,0 +1,63 @@ +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + /** + * Add altering commands here. + * + * Example: + * await queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + return await queryInterface.createTable('columns', { + id: { + type: Sequelize.DataTypes.UUID, + defaultValue: Sequelize.DataTypes.UUIDV4, + primaryKey: true, + }, + name: { + type: Sequelize.DataTypes.STRING, + allowNull: false, + }, + type: { + type: Sequelize.DataTypes.STRING, + allowNull: false, + }, + kind: { + type: Sequelize.DataTypes.STRING, + allowNull: false, + }, + visible: { + type: Sequelize.DataTypes.BOOLEAN, + allowNull: false, + defaultValue: true, + }, + datasetId: { + type: Sequelize.DataTypes.UUID, + allowNull: false, + references: { + model: { + tableName: 'datasets', + }, + key: 'id', + }, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + }, + }); + }, + + async down(queryInterface, Sequelize) { + /** + * Add reverting commands here. + * + * Example: + * await queryInterface.dropTable('users'); + */ + return await queryInterface.dropTable('columns'); + }, +}; diff --git a/db/migrations/20250312093117-create-processes-table.js b/db/migrations/20250312093117-create-processes-table.js new file mode 100644 index 00000000..ade18494 --- /dev/null +++ b/db/migrations/20250312093117-create-processes-table.js @@ -0,0 +1,69 @@ +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + /** + * Add altering commands here. + * + * Example: + * await queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + + return queryInterface.createTable('processes', { + id: { + type: Sequelize.DataTypes.UUID, + defaultValue: Sequelize.DataTypes.UUIDV4, + primaryKey: true, + }, + modelName: { + type: Sequelize.DataTypes.STRING, + allowNull: false, + }, + modelProvider: { + type: Sequelize.DataTypes.STRING, + allowNull: false, + }, + prompt: { + type: Sequelize.DataTypes.STRING, + allowNull: false, + }, + offset: { + type: Sequelize.DataTypes.INTEGER, + defaultValue: 0, + allowNull: false, + }, + limit: { + type: Sequelize.DataTypes.INTEGER, + defaultValue: 10, + allowNull: false, + }, + columnId: { + type: Sequelize.DataTypes.UUID, + allowNull: false, + references: { + model: { + tableName: 'columns', + }, + key: 'id', + }, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + }, + }); + }, + + async down(queryInterface, Sequelize) { + /** + * Add reverting commands here. + * + * Example: + * await queryInterface.dropTable('users'); + */ + return queryInterface.dropTable('processes'); + }, +}; diff --git a/db/migrations/20250312093408-create-process-referred-columns-table.js b/db/migrations/20250312093408-create-process-referred-columns-table.js new file mode 100644 index 00000000..f04043f4 --- /dev/null +++ b/db/migrations/20250312093408-create-process-referred-columns-table.js @@ -0,0 +1,53 @@ +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + /** + * Add altering commands here. + * + * Example: + * await queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + + await queryInterface.createTable( + 'process_referred_columns', + { + processId: { + type: Sequelize.DataTypes.UUID, + allowNull: false, + references: { + model: { + tableName: 'processes', + }, + key: 'id', + }, + }, + columnId: { + type: Sequelize.DataTypes.UUID, + allowNull: false, + references: { + model: { + tableName: 'columns', + }, + key: 'id', + }, + }, + }, + { + uniqueKeys: { + process_referred_columns_unique: { + fields: ['processId', 'columnId'], + }, + }, + }, + ); + }, + + async down(queryInterface, Sequelize) { + /** + * Add reverting commands here. + * + * Example: + * await queryInterface.dropTable('users'); + */ + }, +}; diff --git a/db/migrations/20250312100503-create-cells-table.js b/db/migrations/20250312100503-create-cells-table.js new file mode 100644 index 00000000..d0d682f1 --- /dev/null +++ b/db/migrations/20250312100503-create-cells-table.js @@ -0,0 +1,66 @@ +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + /** + * Add altering commands here. + * + * Example: + * await queryInterface.createTable('users', { id: Sequelize.INTEGER }); + */ + return queryInterface.createTable('cells', { + id: { + type: Sequelize.DataTypes.UUID, + defaultValue: Sequelize.DataTypes.UUIDV4, + primaryKey: true, + }, + idx: { + type: Sequelize.DataTypes.INTEGER, + allowNull: false, + }, + value: { + type: Sequelize.DataTypes.STRING, + allowNull: true, + }, + error: { + type: Sequelize.DataTypes.STRING, + allowNull: true, + }, + validated: { + type: Sequelize.DataTypes.BOOLEAN, + defaultValue: false, + }, + generating: { + type: Sequelize.DataTypes.BOOLEAN, + defaultValue: false, + }, + columnId: { + type: Sequelize.DataTypes.UUID, + allowNull: false, + references: { + model: { + tableName: 'columns', + }, + key: 'id', + }, + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + }, + }); + }, + + async down(queryInterface, Sequelize) { + /** + * Add reverting commands here. + * + * Example: + * await queryInterface.dropTable('users'); + */ + return queryInterface.dropTable('cells'); + }, +}; diff --git a/db/migrations/package.json b/db/migrations/package.json new file mode 100644 index 00000000..5bbefffb --- /dev/null +++ b/db/migrations/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/package.json b/package.json index ad222f27..e096db64 100644 --- a/package.json +++ b/package.json @@ -18,19 +18,21 @@ "build.server": "vite build -c adapters/express/vite.config.ts", "build.types": "tsc --incremental --noEmit", "deploy": "echo 'Run \"npm run qwik add\" to install a server adapter'", - "dev": "vite --mode ssr", + "dev": "pnpm migrate:up && vite --mode ssr", "dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force", "lint": "biome lint . --write ", "lint.check": "biome lint .", "fmt": "biome format . --write", "fmt.check": "biome format .", - "preview": "qwik build preview && vite preview --open", - "serve": "node server/entry.express", + "preview": "pnpm migrate:up --env production && qwik build preview && vite preview --open", + "serve": "pnpm migrate:up --env production && node server/entry.express", "start": "vite --open --mode ssr", - "test": "vitest", + "test": "pnpm migrate:up --env test && vitest", "test.unit.ui": "vitest --ui", "qwik": "qwik", - "prepare": "husky" + "prepare": "husky", + "migrate:up": "sequelize-cli db:migrate", + "migrate:down": "sequelize-cli db:migrate:undo:all" }, "devDependencies": { "@biomejs/biome": "1.9.4", @@ -75,7 +77,8 @@ "mustache": "^4.2.0", "sequelize": "^6.37.5", "sqlite3": "^5.1.7", - "yaml": "^2.7.0" + "yaml": "^2.7.0", + "sequelize-cli": "^6.6.2" }, "pnpm": { "onlyBuiltDependencies": [ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 109f03e8..f1c9a50b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ importers: sequelize: specifier: ^6.37.5 version: 6.37.5(sqlite3@5.1.7) + sequelize-cli: + specifier: ^6.6.2 + version: 6.6.2 sqlite3: specifier: ^5.1.7 version: 5.1.7 @@ -679,6 +682,9 @@ packages: '@oddbird/popover-polyfill@0.4.3': resolution: {integrity: sha512-kBS0ZAwH8kZqFl0mV89KPK4cLYl2ZoKSfYngK4dz1eLAhKzTK0yu4LrvLdMeM7JhjWK6GxBtiY+cl1s6vR2pUg==} + '@one-ini/wasm@0.1.1': + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + '@pkgjs/parseargs@0.11.0': resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -1016,6 +1022,10 @@ packages: abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -1118,6 +1128,10 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + autoprefixer@10.4.20: resolution: {integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==} engines: {node: ^10 || ^12 || >=14} @@ -1147,6 +1161,9 @@ packages: bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + body-parser@1.20.3: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -1251,6 +1268,10 @@ packages: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} + cli-color@2.0.4: + resolution: {integrity: sha512-zlnpg0jNcibNrO7GG9IeHH7maWFeCz+Ja1wx/7tZNU5ASSSSZ+/qZciM0/LHCYxSdqv5h2sdbQ/PXYdOuetXvA==} + engines: {node: '>=0.10'} + cli-cursor@3.1.0: resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} engines: {node: '>=8'} @@ -1259,6 +1280,9 @@ packages: resolution: {integrity: sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==} engines: {node: '>=6'} + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} @@ -1299,6 +1323,10 @@ packages: comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1318,6 +1346,9 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + config-chain@1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + consola@3.4.0: resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} engines: {node: ^14.18.0 || >=16.10.0} @@ -1371,6 +1402,10 @@ packages: csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + d@1.0.2: + resolution: {integrity: sha512-MOqHvMWF9/9MX6nza0KgvFH4HpMU0EF5uUDXqX/BtxtU8NfB0QzRtJ8Oe/6SuS4kbhyzVJwjd97EA4PKrzJ8bw==} + engines: {node: '>=0.12'} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -1488,6 +1523,11 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} + hasBin: true + ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -1553,6 +1593,20 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} + es5-ext@0.10.64: + resolution: {integrity: sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==} + engines: {node: '>=0.10'} + + es6-iterator@2.0.3: + resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==} + + es6-symbol@3.1.4: + resolution: {integrity: sha512-U9bFFjX8tFiATgtkJ1zg25+KviIXpgRvRHS8sau3GfhVzThRQrOeksPeT0BWW2MNZs1OEWJ1DPXOQMn0KKRkvg==} + engines: {node: '>=0.12'} + + es6-weak-map@2.0.3: + resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==} + esast-util-from-estree@2.0.0: resolution: {integrity: sha512-4CyanoAudUSBAn5K13H4JhsMH6L9ZP7XbLVe/dKybkxMO7eDyLsT8UHl9TRNrU2Gr9nz+FovfSIjuXWJ81uVwQ==} @@ -1593,6 +1647,10 @@ packages: deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true + esniff@2.0.1: + resolution: {integrity: sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==} + engines: {node: '>=0.10'} + espree@9.6.1: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -1646,6 +1704,9 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + event-emitter@0.3.5: + resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==} + expand-template@2.0.3: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} @@ -1658,6 +1719,9 @@ packages: resolution: {integrity: sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==} engines: {node: '>= 0.10.0'} + ext@1.7.0: + resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==} + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} @@ -1762,6 +1826,10 @@ packages: fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + fs-minipass@2.1.0: resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} engines: {node: '>= 8'} @@ -2003,6 +2071,9 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} + is-promise@2.2.2: + resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==} + is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -2034,6 +2105,15 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + js-beautify@1.15.4: + resolution: {integrity: sha512-9/KXeZUKKJwqCXUdBxFJ3vPh467OCckSBmYDwSK/EtV090K+iMJ7zx2S3HLVDIWFQdqMIsZWbnaGiba18aWhaA==} + engines: {node: '>=14'} + hasBin: true + + js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} + js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true @@ -2062,6 +2142,9 @@ packages: jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} @@ -2107,6 +2190,9 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lru-queue@0.1.0: + resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==} + magic-string@0.30.17: resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} @@ -2164,6 +2250,10 @@ packages: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} + memoizee@0.4.17: + resolution: {integrity: sha512-DGqD7Hjpi/1or4F/aYAspXKNm5Yili0QDAFAY4QYvpqpgiY6+1jOfqpmByzjxbWd/T9mChbCArXAbDAsTm5oXA==} + engines: {node: '>=0.12'} + merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -2295,6 +2385,10 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} + minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -2392,6 +2486,9 @@ packages: resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} engines: {node: '>= 0.6'} + next-tick@1.1.0: + resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} + node-abi@3.74.0: resolution: {integrity: sha512-c5XK0MjkGBrQPGYG24GBADZud0NCbznxNx0ZkS+ebUTrmV1qTDxPxSL8zEAPURXSbLRWVexxmP4986BziahL5w==} engines: {node: '>=10'} @@ -2415,6 +2512,11 @@ packages: engines: {node: '>=6'} hasBin: true + nopt@7.2.1: + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -2636,6 +2738,9 @@ packages: property-information@7.0.0: resolution: {integrity: sha512-7D/qOz/+Y4X/rzSB6jKxKUsQnphO046ei8qxG59mtM3RG3DHgTK81HrxrmoDVINJb8NKT5ZsRbwHvQ6B68Iyhg==} + proto-list@1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -2783,6 +2888,11 @@ packages: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} + sequelize-cli@6.6.2: + resolution: {integrity: sha512-V8Oh+XMz2+uquLZltZES6MVAD+yEnmMfwfn+gpXcDiwE3jyQygLt4xoI0zG8gKt6cRcs84hsKnXAKDQjG/JAgg==} + engines: {node: '>=10.0.0'} + hasBin: true + sequelize-pool@7.1.0: resolution: {integrity: sha512-G9c0qlIWQSK29pR/5U2JF5dDQeqqHRragoyahj/Nx4KOOQ3CPPfzxnfqFPCSB7x5UgjOgnZ61nSxz+fjDpRlJg==} engines: {node: '>= 10.0.0'} @@ -3029,6 +3139,10 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + timers-ext@0.1.8: + resolution: {integrity: sha512-wFH7+SEAcKfJpfLPkrgMPvvwnEtj8W4IurvEyrKsDleXnKLCDw71w8jltvfLa8Rm4qQxxT4jmDBYbJG/z7qoww==} + engines: {node: '>=0.12'} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -3117,11 +3231,18 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + type@2.7.3: + resolution: {integrity: sha512-8j+1QmAbPvLZow5Qpi6NCaN8FB60p/6x8/vfNqOk/hC+HuvFZhL4+WfekuhQLiqFZXOgQdrs3B+XxEmCc6b3FQ==} + typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} hasBin: true + umzug@2.3.0: + resolution: {integrity: sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==} + engines: {node: '>=6.0.0'} + undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} @@ -3156,6 +3277,10 @@ packages: unist-util-visit@5.0.0: resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -3321,10 +3446,18 @@ packages: engines: {node: '>= 14'} hasBin: true + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + yargs@17.7.2: resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} engines: {node: '>=12'} @@ -3801,6 +3934,8 @@ snapshots: '@oddbird/popover-polyfill@0.4.3': {} + '@one-ini/wasm@0.1.1': {} + '@pkgjs/parseargs@0.11.0': optional: true @@ -4149,6 +4284,8 @@ snapshots: abbrev@1.1.1: optional: true + abbrev@2.0.0: {} + accepts@1.3.8: dependencies: mime-types: 2.1.35 @@ -4237,6 +4374,8 @@ snapshots: asynckit@0.4.0: {} + at-least-node@1.0.0: {} + autoprefixer@10.4.20(postcss@8.5.3): dependencies: browserslist: 4.24.4 @@ -4273,6 +4412,8 @@ snapshots: inherits: 2.0.4 readable-stream: 3.6.2 + bluebird@3.7.2: {} + body-parser@1.20.3: dependencies: bytes: 3.1.2 @@ -4411,12 +4552,26 @@ snapshots: clean-stack@2.2.0: optional: true + cli-color@2.0.4: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + memoizee: 0.4.17 + timers-ext: 0.1.8 + cli-cursor@3.1.0: dependencies: restore-cursor: 3.1.0 cli-spinners@2.6.1: {} + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + cliui@8.0.1: dependencies: string-width: 4.2.3 @@ -4454,6 +4609,8 @@ snapshots: comma-separated-tokens@2.0.3: {} + commander@10.0.1: {} + commander@4.1.1: {} commander@7.2.0: {} @@ -4476,6 +4633,11 @@ snapshots: concat-map@0.0.1: {} + config-chain@1.1.13: + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + consola@3.4.0: {} console-control-strings@1.1.0: @@ -4525,6 +4687,11 @@ snapshots: csstype@3.1.3: {} + d@1.0.2: + dependencies: + es5-ext: 0.10.64 + type: 2.7.3 + debug@2.6.9: dependencies: ms: 2.0.0 @@ -4618,6 +4785,13 @@ snapshots: eastasianwidth@0.2.0: {} + editorconfig@1.0.4: + dependencies: + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.7.1 + ee-first@1.1.1: {} ejs@3.1.10: @@ -4672,6 +4846,31 @@ snapshots: has-tostringtag: 1.0.2 hasown: 2.0.2 + es5-ext@0.10.64: + dependencies: + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + esniff: 2.0.1 + next-tick: 1.1.0 + + es6-iterator@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-symbol: 3.1.4 + + es6-symbol@3.1.4: + dependencies: + d: 1.0.2 + ext: 1.7.0 + + es6-weak-map@2.0.3: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-iterator: 2.0.3 + es6-symbol: 3.1.4 + esast-util-from-estree@2.0.0: dependencies: '@types/estree-jsx': 1.0.5 @@ -4770,6 +4969,13 @@ snapshots: transitivePeerDependencies: - supports-color + esniff@2.0.1: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + event-emitter: 0.3.5 + type: 2.7.3 + espree@9.6.1: dependencies: acorn: 8.14.0 @@ -4827,6 +5033,11 @@ snapshots: etag@1.8.1: {} + event-emitter@0.3.5: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + expand-template@2.0.3: {} expect-type@1.2.0: {} @@ -4867,6 +5078,10 @@ snapshots: transitivePeerDependencies: - supports-color + ext@1.7.0: + dependencies: + type: 2.7.3 + extend@3.0.2: {} fast-deep-equal@3.1.3: {} @@ -4968,6 +5183,13 @@ snapshots: fs-constants@1.0.0: {} + fs-extra@9.1.0: + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + fs-minipass@2.1.0: dependencies: minipass: 3.3.6 @@ -5056,8 +5278,7 @@ snapshots: gopd@1.2.0: {} - graceful-fs@4.2.11: - optional: true + graceful-fs@4.2.11: {} graphemer@1.4.0: {} @@ -5247,6 +5468,8 @@ snapshots: is-plain-obj@4.1.0: {} + is-promise@2.2.2: {} + is-unicode-supported@0.1.0: {} is-wsl@2.2.0: @@ -5279,6 +5502,16 @@ snapshots: jiti@1.21.7: {} + js-beautify@1.15.4: + dependencies: + config-chain: 1.1.13 + editorconfig: 1.0.4 + glob: 10.4.5 + js-cookie: 3.0.5 + nopt: 7.2.1 + + js-cookie@3.0.5: {} + js-yaml@3.14.1: dependencies: argparse: 1.0.10 @@ -5301,6 +5534,12 @@ snapshots: jsonc-parser@3.2.0: {} + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + keyv@4.5.4: dependencies: json-buffer: 3.0.1 @@ -5340,6 +5579,10 @@ snapshots: yallist: 4.0.0 optional: true + lru-queue@0.1.0: + dependencies: + es5-ext: 0.10.64 + magic-string@0.30.17: dependencies: '@jridgewell/sourcemap-codec': 1.5.0 @@ -5478,6 +5721,17 @@ snapshots: media-typer@0.3.0: {} + memoizee@0.4.17: + dependencies: + d: 1.0.2 + es5-ext: 0.10.64 + es6-weak-map: 2.0.3 + event-emitter: 0.3.5 + is-promise: 2.2.2 + lru-queue: 0.1.0 + next-tick: 1.1.0 + timers-ext: 0.1.8 + merge-descriptors@1.0.3: {} merge2@1.4.1: {} @@ -5719,6 +5973,10 @@ snapshots: dependencies: brace-expansion: 2.0.1 + minimatch@9.0.1: + dependencies: + brace-expansion: 2.0.1 + minimatch@9.0.3: dependencies: brace-expansion: 2.0.1 @@ -5805,6 +6063,8 @@ snapshots: negotiator@0.6.4: {} + next-tick@1.1.0: {} + node-abi@3.74.0: dependencies: semver: 7.7.1 @@ -5837,6 +6097,10 @@ snapshots: abbrev: 1.1.1 optional: true + nopt@7.2.1: + dependencies: + abbrev: 2.0.0 + normalize-path@3.0.0: {} normalize-range@0.1.2: {} @@ -6088,6 +6352,8 @@ snapshots: property-information@7.0.0: {} + proto-list@1.2.4: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -6318,6 +6584,16 @@ snapshots: transitivePeerDependencies: - supports-color + sequelize-cli@6.6.2: + dependencies: + cli-color: 2.0.4 + fs-extra: 9.1.0 + js-beautify: 1.15.4 + lodash: 4.17.21 + resolve: 1.22.10 + umzug: 2.3.0 + yargs: 16.2.0 + sequelize-pool@7.1.0: {} sequelize@6.37.5(sqlite3@5.1.7): @@ -6635,6 +6911,11 @@ snapshots: dependencies: any-promise: 1.3.0 + timers-ext@0.1.8: + dependencies: + es5-ext: 0.10.64 + next-tick: 1.1.0 + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -6699,8 +6980,14 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + type@2.7.3: {} + typescript@5.4.5: {} + umzug@2.3.0: + dependencies: + bluebird: 3.7.2 + undici-types@5.26.5: {} undici@7.3.0: {} @@ -6752,6 +7039,8 @@ snapshots: unist-util-is: 6.0.0 unist-util-visit-parents: 6.0.1 + universalify@2.0.1: {} + unpipe@1.0.0: {} update-browserslist-db@1.1.2(browserslist@4.24.4): @@ -6914,8 +7203,20 @@ snapshots: yaml@2.7.0: {} + yargs-parser@20.2.9: {} + yargs-parser@21.1.1: {} + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + yargs@17.7.2: dependencies: cliui: 8.0.1 diff --git a/src/services/db/models/cell.ts b/src/services/db/models/cell.ts index a99026e6..f47f22a0 100644 --- a/src/services/db/models/cell.ts +++ b/src/services/db/models/cell.ts @@ -63,6 +63,6 @@ ColumnCellModel.init( }, { sequelize: db, - modelName: 'Cell', + tableName: 'cells', }, ); diff --git a/src/services/db/models/column.ts b/src/services/db/models/column.ts index c3f828f0..f1c5d00f 100644 --- a/src/services/db/models/column.ts +++ b/src/services/db/models/column.ts @@ -11,7 +11,7 @@ import sequelize from 'sequelize/lib/sequelize'; import { db } from '~/services/db'; import { ColumnCellModel } from '~/services/db/models/cell'; import type { DatasetModel } from '~/services/db/models/dataset'; -import { ProcessModel } from '~/services/db/models/process'; +import type { ProcessModel } from '~/services/db/models/process'; export class ColumnModel extends Model< InferAttributes, @@ -78,7 +78,7 @@ ColumnModel.init( }, { sequelize: db, - modelName: 'Column', + tableName: 'columns', defaultScope: { attributes: { include: [ @@ -95,49 +95,3 @@ ColumnModel.init( }, }, ); - -ColumnModel.hasMany(ColumnCellModel, { - sourceKey: 'id', - foreignKey: 'columnId', - as: 'cells', -}); - -ColumnCellModel.belongsTo(ColumnModel, { - foreignKey: 'columnId', - as: 'column', -}); - -ColumnModel.hasOne(ProcessModel, { - sourceKey: 'id', - foreignKey: 'columnId', - as: 'process', -}); - -export const ProcessColumnModel = db.define('ProcessColumn', { - processId: { - type: DataTypes.UUID, - allowNull: false, - references: { - model: ProcessModel, - key: 'id', - }, - }, - columnId: { - type: DataTypes.UUID, - allowNull: false, - references: { - model: ColumnModel, - key: 'id', - }, - }, -}); - -ProcessModel.belongsToMany(ColumnModel, { - through: ProcessColumnModel, - as: 'referredColumns', - foreignKey: 'processId', -}); -ColumnModel.belongsToMany(ProcessModel, { - through: ProcessColumnModel, - foreignKey: 'columnId', -}); diff --git a/src/services/db/models/dataset.ts b/src/services/db/models/dataset.ts index 692256f1..9dceed22 100644 --- a/src/services/db/models/dataset.ts +++ b/src/services/db/models/dataset.ts @@ -9,7 +9,7 @@ import { } from 'sequelize'; import { db } from '~/services/db'; -import { ColumnModel } from '~/services/db/models/column'; +import type { ColumnModel } from '~/services/db/models/column'; //Review the path export class DatasetModel extends Model< @@ -48,18 +48,6 @@ DatasetModel.init( }, { sequelize: db, - modelName: 'Dataset', + tableName: 'datasets', }, ); - -DatasetModel.hasMany(ColumnModel, { - sourceKey: 'id', - foreignKey: 'datasetId', - as: 'columns', -}); - -ColumnModel.belongsTo(DatasetModel, { - targetKey: 'id', - foreignKey: 'datasetId', - as: 'dataset', -}); diff --git a/src/services/db/models/index.ts b/src/services/db/models/index.ts index 4ce73cc5..a9e5d0ac 100644 --- a/src/services/db/models/index.ts +++ b/src/services/db/models/index.ts @@ -1,9 +1,56 @@ -import { isDev } from '@builder.io/qwik'; -import { db } from '~/services/db'; +import { ColumnCellModel } from './cell'; +import { ColumnModel } from './column'; +import { DatasetModel } from './dataset'; +import { ProcessModel, ProcessReferredColumnsModel } from './process'; export * from './dataset'; export * from './column'; export * from './cell'; export * from './process'; -await db.sync({ force: isDev }); +// Define associations + +DatasetModel.hasMany(ColumnModel, { + sourceKey: 'id', + foreignKey: 'datasetId', + as: 'columns', +}); + +ColumnModel.belongsTo(DatasetModel, { + targetKey: 'id', + foreignKey: 'datasetId', + as: 'dataset', +}); + +ColumnModel.hasOne(ProcessModel, { + sourceKey: 'id', + foreignKey: 'columnId', + as: 'process', +}); + +ProcessModel.belongsTo(ColumnModel, { + foreignKey: 'columnId', + as: 'column', +}); + +ProcessModel.belongsToMany(ColumnModel, { + through: ProcessReferredColumnsModel, + as: 'referredColumns', + foreignKey: 'processId', +}); +ColumnModel.belongsToMany(ProcessModel, { + through: ProcessReferredColumnsModel, + foreignKey: 'columnId', +}); + +ColumnModel.hasMany(ColumnCellModel, { + sourceKey: 'id', + foreignKey: 'columnId', + as: 'cells', +}); + +ColumnCellModel.belongsTo(ColumnModel, { + targetKey: 'id', + foreignKey: 'columnId', + as: 'column', +}); diff --git a/src/services/db/models/process.ts b/src/services/db/models/process.ts index c5da6516..e84b7fd3 100644 --- a/src/services/db/models/process.ts +++ b/src/services/db/models/process.ts @@ -10,7 +10,7 @@ import { } from 'sequelize'; import { db } from '~/services/db'; -import type { ColumnModel } from '~/services/db/models/column'; +import { ColumnModel } from '~/services/db/models/column'; export class ProcessModel extends Model< InferAttributes, @@ -31,6 +31,7 @@ export class ProcessModel extends Model< declare static associations: { referredColumns: Association; + column: Association; }; } @@ -68,6 +69,33 @@ ProcessModel.init( }, { sequelize: db, - modelName: 'Process', + tableName: 'processes', + }, +); + +export const ProcessReferredColumnsModel = db.define( + 'ProcessReferredColumnsModel', + { + processId: { + type: DataTypes.UUID, + allowNull: false, + references: { + model: ProcessModel, + key: 'id', + }, + }, + columnId: { + type: DataTypes.UUID, + allowNull: false, + references: { + model: ColumnModel, + key: 'id', + }, + }, + }, + { + tableName: 'process_referred_columns', + createdAt: false, + updatedAt: false, }, ); diff --git a/src/services/repository/columns.spec.tsx b/src/services/repository/columns.spec.tsx index 34918c1f..435af919 100644 --- a/src/services/repository/columns.spec.tsx +++ b/src/services/repository/columns.spec.tsx @@ -1,6 +1,9 @@ import { afterEach, describe, expect, it } from 'vitest'; -import { ColumnModel, ProcessColumnModel } from '../db/models/column'; -import { ProcessModel } from '../db/models/process'; +import { ColumnModel } from '../db/models/column'; +import { + ProcessModel, + ProcessReferredColumnsModel, +} from '../db/models/process'; import { DatasetModel } from '../db/models'; import { createColumn } from './columns'; @@ -83,7 +86,7 @@ describe('addColumn', () => { expect(await ColumnModel.count()).toBe(3); expect(await ProcessModel.count()).toBe(1); - expect(await ProcessColumnModel.count()).toBe(2); + expect(await ProcessReferredColumnsModel.count()).toBe(2); const process = await ProcessModel.findOne({ where: { id: newColumn.process!.id }, diff --git a/src/services/repository/processes.ts b/src/services/repository/processes.ts index ba250513..a66e1254 100644 --- a/src/services/repository/processes.ts +++ b/src/services/repository/processes.ts @@ -1,4 +1,7 @@ -import { ProcessColumnModel, ProcessModel } from '~/services/db/models'; +import { + ProcessModel, + ProcessReferredColumnsModel, +} from '~/services/db/models'; import type { Process } from '~/state'; export interface CreateProcess { @@ -30,7 +33,11 @@ export const createProcess = async ({ // TODO: Try to create junction model when creating a process if ((process.columnsReferences ?? []).length > 0) { - await ProcessColumnModel.bulkCreate( + await ProcessReferredColumnsModel.destroy({ + where: { processId: model.id }, + }); + + await ProcessReferredColumnsModel.bulkCreate( process.columnsReferences!.map((columnId) => { return { processId: model.id, columnId }; }), @@ -68,8 +75,10 @@ export const updateProcess = async (process: Process): Promise => { await model.save(); if ((process.columnsReferences ?? []).length > 0) { - await ProcessColumnModel.destroy({ where: { processId: process.id } }); - await ProcessColumnModel.bulkCreate( + await ProcessReferredColumnsModel.destroy({ + where: { processId: process.id }, + }); + await ProcessReferredColumnsModel.bulkCreate( process.columnsReferences!.map((columnId) => { return { processId: process.id, columnId }; }),