From 328ab61757627abc6b04c9bcc86f63168926e9bd Mon Sep 17 00:00:00 2001 From: Fabio Di Stasio Date: Wed, 16 Feb 2022 09:14:46 +0100 Subject: [PATCH] Merge branch 'master' of https://github.com/Fabio286/antares into pr/toriphes/129 --- .all-contributorsrc | 32 +- .eslintignore | 8 +- .eslintrc | 8 +- .github/workflows/build-linux.yml | 8 +- .github/workflows/build-mac.yml | 8 +- .github/workflows/build-win.yml | 8 +- .vscode/settings.json | 4 +- CHANGELOG.md | 122 +++ README.md | 18 +- assets/appx/LargeTile.png | Bin 55079 -> 0 bytes assets/appx/SmallTile.png | Bin 7572 -> 0 bytes assets/appx/Square150x150Logo.png | Bin 23097 -> 6414 bytes assets/appx/Square44x44Logo.png | Bin 4112 -> 4377 bytes assets/appx/StoreLogo.png | Bin 42634 -> 5257 bytes assets/appx/Wide310x150Logo.png | Bin 17118 -> 7605 bytes package.json | 43 +- scripts/devRunner.js | 11 +- src/common/FakerMethods.js | 2 +- src/common/customizations/defaults.js | 16 +- src/common/customizations/index.js | 3 +- src/common/customizations/mysql.js | 7 +- src/common/customizations/postgresql.js | 9 +- src/common/customizations/sqlite.js | 27 + src/common/data-types/mysql.js | 21 +- src/common/data-types/postgresql.js | 11 +- src/common/data-types/sqlite.js | 137 +++ src/common/fieldTypes.js | 25 +- src/common/index-types/sqlite.js | 5 + src/common/libs/getArrayDepth.js | 10 + src/main/ipc-handlers/connection.js | 14 +- src/main/ipc-handlers/schedulers.js | 13 + src/main/ipc-handlers/schema.js | 51 +- src/main/ipc-handlers/tables.js | 18 +- src/main/ipc-handlers/triggers.js | 13 + src/main/ipc-handlers/updates.js | 9 +- src/main/libs/ClientsFactory.js | 3 + src/main/libs/clients/MySQLClient.js | 283 ++++-- src/main/libs/clients/PostgreSQLClient.js | 289 ++++-- src/main/libs/clients/SQLiteClient.js | 859 ++++++++++++++++++ src/main/main.js | 38 +- src/renderer/components/BaseMap.vue | 108 +++ src/renderer/components/FakerSelect.vue | 2 +- .../components/ModalAskParameters.vue | 8 +- .../components/ModalDiscardChanges.vue | 6 +- src/renderer/components/ModalExportSchema.vue | 2 +- src/renderer/components/ModalFakerRows.vue | 8 +- src/renderer/components/ModalHistory.vue | 1 + .../components/ModalProcessesListRow.vue | 6 +- src/renderer/components/ModalSettings.vue | 2 +- .../components/ModalSettingsChangelog.vue | 2 +- .../components/ModalSettingsUpdate.vue | 16 +- src/renderer/components/SettingBarContext.vue | 6 +- src/renderer/components/TheFooter.vue | 6 +- .../components/TheNotificationsBoard.vue | 21 +- src/renderer/components/TheScratchpad.vue | 6 +- src/renderer/components/TheSettingBar.vue | 4 +- src/renderer/components/Workspace.vue | 121 +-- .../WorkspaceAddConnectionPanel.vue | 61 +- .../WorkspaceEditConnectionPanel.vue | 55 +- .../components/WorkspaceExploreBar.vue | 1 + .../WorkspaceExploreBarMiscContext.vue | 97 +- .../components/WorkspaceExploreBarSchema.vue | 46 +- .../WorkspaceExploreBarSchemaContext.vue | 12 +- .../WorkspaceExploreBarTableContext.vue | 12 +- .../components/WorkspaceTabNewTable.vue | 19 +- .../components/WorkspaceTabPropsFunction.vue | 2 +- .../WorkspaceTabPropsFunctionParamsModal.vue | 30 +- .../components/WorkspaceTabPropsRoutine.vue | 2 +- .../WorkspaceTabPropsRoutineParamsModal.vue | 26 +- .../WorkspaceTabPropsSchedulerTimingModal.vue | 6 +- .../components/WorkspaceTabPropsTable.vue | 68 +- .../WorkspaceTabPropsTableContext.vue | 2 +- .../WorkspaceTabPropsTableFields.vue | 8 +- .../WorkspaceTabPropsTableForeignModal.vue | 30 +- .../WorkspaceTabPropsTableIndexesModal.vue | 26 +- .../components/WorkspaceTabPropsTableRow.vue | 49 +- .../WorkspaceTabPropsTriggerFunction.vue | 2 +- src/renderer/components/WorkspaceTabQuery.vue | 182 +++- .../WorkspaceTabQueryEmptyState.vue | 11 +- .../components/WorkspaceTabQueryTable.vue | 66 +- .../WorkspaceTabQueryTableContext.vue | 2 - .../components/WorkspaceTabQueryTableRow.vue | 138 ++- src/renderer/components/WorkspaceTabTable.vue | 12 +- src/renderer/i18n/en-US.js | 18 +- src/renderer/i18n/index.js | 3 +- src/renderer/i18n/it-IT.js | 23 +- src/renderer/i18n/supported-locales.js | 3 +- src/renderer/i18n/vi-VN.js | 11 +- src/renderer/i18n/zh-CN.js | 421 +++++++++ .../images/svg/{sqllite.svg => sqlite.svg} | 0 src/renderer/index.js | 1 + src/renderer/ipc-api/Schedulers.js | 4 + src/renderer/ipc-api/Schema.js | 16 + src/renderer/ipc-api/Triggers.js | 4 + src/renderer/scss/_data-types.scss | 13 + src/renderer/scss/_db-icons.scss | 4 + src/renderer/scss/main.scss | 28 + src/renderer/scss/themes/dark-theme.scss | 2 +- .../store/modules/connections.store.js | 24 +- .../store/modules/workspaces.store.js | 5 + src/renderer/store/plugins/ipcUpdates.js | 10 + tests/app.spec.js | 49 + 102 files changed, 3499 insertions(+), 563 deletions(-) delete mode 100644 assets/appx/LargeTile.png delete mode 100644 assets/appx/SmallTile.png create mode 100644 src/common/customizations/sqlite.js create mode 100644 src/common/data-types/sqlite.js create mode 100644 src/common/index-types/sqlite.js create mode 100644 src/common/libs/getArrayDepth.js create mode 100644 src/main/libs/clients/SQLiteClient.js create mode 100644 src/renderer/components/BaseMap.vue create mode 100644 src/renderer/i18n/zh-CN.js rename src/renderer/images/svg/{sqllite.svg => sqlite.svg} (100%) create mode 100644 tests/app.spec.js diff --git a/.all-contributorsrc b/.all-contributorsrc index 39e1aa91..531e03bd 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1,5 +1,5 @@ { - "projectName": "Antares", + "projectName": "antares", "projectOwner": "Fabio286", "repoType": "github", "repoHost": "https://github.com", @@ -111,7 +111,35 @@ "contributions": [ "platform" ] + }, + { + "login": "kilianstallz", + "name": "Kilian Stallinger", + "avatar_url": "https://avatars.githubusercontent.com/u/5290318?v=4", + "profile": "https://kilianstallinger.com", + "contributions": [ + "code" + ] + }, + { + "login": "wenj91", + "name": "文杰", + "avatar_url": "https://avatars.githubusercontent.com/u/12549338?v=4", + "profile": "https://github.com/wenj91", + "contributions": [ + "code" + ] + }, + { + "login": "goYou", + "name": "goYou", + "avatar_url": "https://avatars.githubusercontent.com/u/62732795?v=4", + "profile": "https://github.com/goYou", + "contributions": [ + "translation" + ] } ], - "contributorsPerLine": 7 + "contributorsPerLine": 7, + "skipCi": true } diff --git a/.eslintignore b/.eslintignore index c87fbd4d..d3405a7a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,4 +1,4 @@ -/node_modules -/assets/vendor -/out -/dist \ No newline at end of file +node_modules +assets +out +dist \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 5c86654c..54031e45 100644 --- a/.eslintrc +++ b/.eslintrc @@ -45,6 +45,7 @@ "no-console": "off", "no-undef": "off", "vue/no-side-effects-in-computed-properties": "off", + "vue/multi-word-component-names": "off", "vue/require-default-prop": "off", "vue/comment-directive": "off", "vue/no-v-html": "off", @@ -61,10 +62,11 @@ "vue/max-attributes-per-line": [ "error", { - "singleline": 2, + "singleline": { + "max": 2 + }, "multiline": { - "max": 1, - "allowFirstLine": false + "max": 1 } } ] diff --git a/.github/workflows/build-linux.yml b/.github/workflows/build-linux.yml index d0a63f9c..edb77ac1 100644 --- a/.github/workflows/build-linux.yml +++ b/.github/workflows/build-linux.yml @@ -12,12 +12,18 @@ jobs: steps: - name: Check out Git repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Install Node.js, NPM and Yarn uses: actions/setup-node@v1 with: node-version: 14 + + - name: Install dependencies + run: npm i + + - name: Run tests + run: npm run test - name: Build/release Electron app uses: samuelmeuli/action-electron-builder@v1 diff --git a/.github/workflows/build-mac.yml b/.github/workflows/build-mac.yml index 95679142..9981e0a8 100644 --- a/.github/workflows/build-mac.yml +++ b/.github/workflows/build-mac.yml @@ -12,12 +12,18 @@ jobs: steps: - name: Check out Git repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Install Node.js, NPM and Yarn uses: actions/setup-node@v1 with: node-version: 14 + + - name: Install dependencies + run: npm i + + - name: Run tests + run: npm run test - name: Build/release Electron app uses: samuelmeuli/action-electron-builder@v1 diff --git a/.github/workflows/build-win.yml b/.github/workflows/build-win.yml index 7495faa5..747902d8 100644 --- a/.github/workflows/build-win.yml +++ b/.github/workflows/build-win.yml @@ -12,13 +12,19 @@ jobs: steps: - name: Check out Git repository - uses: actions/checkout@v1 + uses: actions/checkout@v2 - name: Install Node.js, NPM and Yarn uses: actions/setup-node@v1 with: node-version: 14 + - name: Install dependencies + run: npm i + + - name: Run tests + run: npm run test + - name: Build/release Electron app uses: samuelmeuli/action-electron-builder@v1 with: diff --git a/.vscode/settings.json b/.vscode/settings.json index 5b0c8130..768edbfb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,9 @@ "UI", "core", "MySQL", - "PostgreSQL" + "PostgreSQL", + "SQLite", + "Windows" ], "svg.preview.background": "transparent" } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 0402fdd1..eef86af4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,128 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [0.4.3](https://github.com/Fabio286/antares/compare/v0.4.2...v0.4.3) (2022-01-30) + + +### Features + +* add Simplified Chinese translation ([6ef565c](https://github.com/Fabio286/antares/commit/6ef565cf078cb3f5b7bcdc226894cddeb6239db9)) +* **MySQL:** spatial fields support ([#165](https://github.com/Fabio286/antares/issues/165)) ([48ebf23](https://github.com/Fabio286/antares/commit/48ebf23bd1574408f429f2e1200ce878352007f6)) + + +### Bug Fixes + +* cell copy returns "undefined" in some conditions, closes [#170](https://github.com/Fabio286/antares/issues/170) ([8fb1f08](https://github.com/Fabio286/antares/commit/8fb1f0803efd9df0b66521e73bb6e1a229cf9691)) +* indexes and foreign keys not cleared after deletion of related field, closes [#182](https://github.com/Fabio286/antares/issues/182) ([9f033fb](https://github.com/Fabio286/antares/commit/9f033fb994916b4fb165e81e55e86127ca817791)) +* **PostgreSQL:** schema different than public not automatically selected, closes [#172](https://github.com/Fabio286/antares/issues/172) ([46b45c8](https://github.com/Fabio286/antares/commit/46b45c8ab64fb6837a532c4f8342167e4fd794bb)) +* scale on numeric fields that doesn't support it ([0cfd793](https://github.com/Fabio286/antares/commit/0cfd7938ee7d607dbad66ae452d0200223a6bab2)) +* **Windows:** temporary fix to Windows 7 style frame on app startup, closes [#169](https://github.com/Fabio286/antares/issues/169) ([1356011](https://github.com/Fabio286/antares/commit/1356011ba3b7dd72e12cb252a8787ce48a364fd4)) + + +### Improvements + +* support of scale in field's length setting ([eef7c1d](https://github.com/Fabio286/antares/commit/eef7c1dcecc6593ab0e69ed678187a57fe0a4fb6)) + +### [0.4.2](https://github.com/Fabio286/antares/compare/v0.4.1...v0.4.2) (2022-01-10) + + +### Features + +* **MySQL:** ability to cancel queries ([a59f77f](https://github.com/Fabio286/antares/commit/a59f77f618aea6156fc80fb832d3efcb9848411f)) +* **PostgreSQL:** ability to cancel queries ([0c00291](https://github.com/Fabio286/antares/commit/0c002918eb0226f6b3f21ed62117495f86396fb1)) +* save window state ([8f9385d](https://github.com/Fabio286/antares/commit/8f9385d50815635d091758ecd5d00884e3297ca0)) +* **UI:** textarea autofocus selecting a query tab, closes [#166](https://github.com/Fabio286/antares/issues/166) ([b4545b1](https://github.com/Fabio286/antares/commit/b4545b178f795712c781a3f4fc35eec31b5ad902)) + + +### Bug Fixes + +* **SQLite:** exception with some fields ([e7a1858](https://github.com/Fabio286/antares/commit/e7a18580915e7739bfa97948c6a0c4fc90a7e78a)) + + +### Improvements + +* hash for foreign key default names ([48c3e6a](https://github.com/Fabio286/antares/commit/48c3e6afc43c51f70a16703f1a71194f43da7a3e)) +* **MySQL:** support to ANSI_QUOTES sql_mode, closes [#158](https://github.com/Fabio286/antares/issues/158) ([d9a3eab](https://github.com/Fabio286/antares/commit/d9a3eab015302e9f23112f659658073ab3242191)) + +### [0.4.1](https://github.com/Fabio286/antares/compare/v0.4.0...v0.4.1) (2021-12-11) + + +### Features + +* language format detection for text fields ([a5fdcc1](https://github.com/Fabio286/antares/commit/a5fdcc1a85aa188ff1b9a15b1a768aced026f360)) + + +### Bug Fixes + +* cell disappear on edit in one column tables ([aaa5549](https://github.com/Fabio286/antares/commit/aaa5549609664665bd4513632d621cb249b379c1)) +* false positive with Windows Defender ([992a033](https://github.com/Fabio286/antares/commit/992a033cb2bede3d1eb52e19482d810f6692de1e)) +* **MySQL:** wrong datetime fields default in table filler in some cases ([8da0224](https://github.com/Fabio286/antares/commit/8da022487650039b7f34a9c86a7bd9045eba65e2)) +* **MySQL:** wrong value for fields "on update" in some conditions ([359e14a](https://github.com/Fabio286/antares/commit/359e14a9ebd48f86069ba7762fe00a7056f52d47)) +* select all rows with ctrl+a when editing a cell ([35cb7e1](https://github.com/Fabio286/antares/commit/35cb7e1dc48d3a74e9d106cb1a37f454c1b4a4d1)) +* **SQLite:** update rows with a text primary key ([d7f1aa9](https://github.com/Fabio286/antares/commit/d7f1aa97af32a4c51fc7022498bd47e15fa08430)) + + +### Improvements + +* **UI:** avoid columns size change when editing cells or scrolling results ([813aa32](https://github.com/Fabio286/antares/commit/813aa320d9ab799efea38a7110b7c0bdf7549123)) +* **UI:** disable save button in table creation when no fields are added ([e8af2d2](https://github.com/Fabio286/antares/commit/e8af2d24a869f7667c069936648808952d2062ab)) + +## [0.4.0](https://github.com/Fabio286/antares/compare/v0.3.9...v0.4.0) (2021-11-24) + + +### Features + +* **MySQL:** read-only mode ([4437d44](https://github.com/Fabio286/antares/commit/4437d44486c4f20b0bec4bf89d56016b08e36e79)) +* **PostgreSQL:** read-only mode ([5d48fe0](https://github.com/Fabio286/antares/commit/5d48fe08c77755ed18b3f7a9ea834268e317e7ef)) +* **SQLite:** cell update in data tabs ([604b371](https://github.com/Fabio286/antares/commit/604b3719204f7473ce4846624f08f8be9eec8b8f)) +* **SQLite:** connection add/edit masks ([c54438d](https://github.com/Fabio286/antares/commit/c54438d6d3bad38bc76dfcd61f58929fe30279cb)) +* **SQLite:** keys support ([fd321be](https://github.com/Fabio286/antares/commit/fd321beece075d3ad23fdd8541f9beb5727045a5)) +* **SQLite:** readonly mode ([3fc227d](https://github.com/Fabio286/antares/commit/3fc227d2de53aae115226ad3c965bfb6e9f3eca6)) +* **SQLite:** table data visualization ([f2fcc98](https://github.com/Fabio286/antares/commit/f2fcc9883972402eab4d51ef2a9796638dde2d3d)) +* **SQLite:** tables management ([3efeb45](https://github.com/Fabio286/antares/commit/3efeb45c460f178b794de72367f8d542fd8ddd56)) +* **SQLite:** triggers management ([f40e9c5](https://github.com/Fabio286/antares/commit/f40e9c592eeffd204aba21a0a0767a0c523fca49)) +* **SQLite:** views management ([7671c58](https://github.com/Fabio286/antares/commit/7671c585f5f8049bd863db190d4fc60d8f0c6c66)) + + +### Bug Fixes + +* **SQLite:** hide schema creation ([98165ca](https://github.com/Fabio286/antares/commit/98165cacaa158c85ead0490d3caf579e2a17319f)) +* **UI:** hide tools menu if no tools available ([da1947e](https://github.com/Fabio286/antares/commit/da1947e4efa7f0a26d6a231fadf750be055fbdd5)) +* **UI:** notifications timeout anomalies ([cc99491](https://github.com/Fabio286/antares/commit/cc99491fe4a15812368f6c928b8c7801d7b255aa)) + + +### Improvements + +* **SQLite:** improvements in data visualization ([94c899e](https://github.com/Fabio286/antares/commit/94c899eb8288b41a5962ac3d24365227e1f9f485)) +* **SQLite:** improvements in field length detection ([93b4a70](https://github.com/Fabio286/antares/commit/93b4a7063beeb5a7001cb06a74f05b23105212f5)) +* update italian traslation ([9fe3680](https://github.com/Fabio286/antares/commit/9fe3680bbb17c192cffa85348e68794ab49beb81)) + +### [0.3.9](https://github.com/Fabio286/antares/compare/v0.3.8...v0.3.9) (2021-11-14) + + +### Features + +* added macos basic shortcusts and menu ([430490a](https://github.com/Fabio286/antares/commit/430490ad93f3148962ced1f13a5330c79cd86b3b)) +* **MySQL:** enable/disable schedulers from contextual menu ([5ca3a22](https://github.com/Fabio286/antares/commit/5ca3a22dc538b27a4bf6402f1288c4b9f5bc5a90)) +* **MySQL:** scheduler status indicator in explore bar ([5c66824](https://github.com/Fabio286/antares/commit/5c668249cf102cd9d601f9f7b4943c7155775217)) +* **PostgreSQL:** enable/disable triggers from contextual menu ([534659f](https://github.com/Fabio286/antares/commit/534659f9aee12eb5ac477f91bfe5d764387dc17e)) +* schema size in explore bar ([fd25f88](https://github.com/Fabio286/antares/commit/fd25f881f95779709156cbad93a41d6b391f1a45)) +* **UI:** double click on the title bar will toggle window fullscreen size ([a35566f](https://github.com/Fabio286/antares/commit/a35566f273322602abe434b8bd30817ba8885900)) +* **UI:** improved topbar look&feel on MacOS ([7657d05](https://github.com/Fabio286/antares/commit/7657d05edfbeaed6a14eb337fc562da5126e6ba0)) + + +### Bug Fixes + +* copy&paste and basic usability on macOS ([1ddf8f0](https://github.com/Fabio286/antares/commit/1ddf8f0dbe22f94d6bffddf70636706d2d142ecf)) +* **PostgreSQL:** bigint fetched as string instead of number, closes [#134](https://github.com/Fabio286/antares/issues/134) ([39b9a59](https://github.com/Fabio286/antares/commit/39b9a59143b457a96f0711a3b8588c92dd80e28d)) +* row selection problems after a deletion fail, closes [#128](https://github.com/Fabio286/antares/issues/128) ([89fdd21](https://github.com/Fabio286/antares/commit/89fdd210ca48fc9ae399b195ea796c8523619627)) +* temporary solution on MacOS for unsigned app updates ([c00fd13](https://github.com/Fabio286/antares/commit/c00fd1381f451ba7aace7047b28b904ddcaf18f0)) + + +### Improvements + +* **UI:** improved function and routine parameters modals ([d19f475](https://github.com/Fabio286/antares/commit/d19f475fc28c0367ada569cb634769fa618b48b4)) + ### [0.3.8](https://github.com/Fabio286/antares/compare/v0.3.7...v0.3.8) (2021-10-23) diff --git a/README.md b/README.md index af1fe470..c0aa199b 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Antares is an SQL client based on [Electron.js](https://github.com/electron/electron) and [Vue.js](https://github.com/vuejs/vue) that aims to become a useful tool, especially for developers. Our target is to support as many databases as possible, and all major operating systems, including the ARM versions. -**At the moment this application is in development state, many features will come in future updates**, and supports only MySQL/MariaDB and PostgreSQL. +**At the moment this application is in development state, many features will come in future updates**, and supports only MySQL/MariaDB, PostgreSQL and SQLite. At the moment, however, there are all the features necessary to have a pleasant database management experience, so give it a chance and send us your feedback, we would really appreciate it. We are actively working on it, hoping to provide new cool features, improvements and fixes as soon as possible. @@ -31,10 +31,9 @@ We are actively working on it, hoping to provide new cool features, improvements - Query suggestions and auto complete. - Query history: search through the last 1000 queries. - SSH tunnel support. +- Manual commit mode. - Dark and light theme. - Editor themes. -- Scratchpad. -- Secure password storage. ## Philosophy @@ -68,12 +67,12 @@ On macOS you can run `.dmg` distribution following [this guide](https://support. This is a roadmap with major features will come in near future. -- Support for other databases. - Database tools. - Users management (add/edit/delete). - More context menu shortcuts. - More keyboard shortcuts. - Import/export and migration. +- Support for other databases. - Apple Silicon distribution ## Currently supported @@ -82,7 +81,7 @@ This is a roadmap with major features will come in near future. - [x] MySQL/MariaDB - [x] PostgreSQL -- [ ] SQLite +- [x] SQLite - [ ] MSSQL - [ ] OracleDB - [ ] More... @@ -116,9 +115,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d - - - + + + @@ -129,6 +128,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d + + +

Fabio Di Stasio

💻 🌍 📖

Giulio Ganci

💻

Christian Ratz

💻 🌍

Fabio Di Stasio

💻 🌍 📖

Giulio Ganci

💻

Christian Ratz

💻 🌍

Giuseppe Gigliotti

🌍

Mohd-PH

🌍

hongkfui

🌍

Ngô Quốc Đạt

🌍

Isamu Sugiura

🌍

Riccardo Sacchetto

📦

Kilian Stallinger

💻

文杰

💻

goYou

🌍
diff --git a/assets/appx/LargeTile.png b/assets/appx/LargeTile.png deleted file mode 100644 index afef8cac9bc414978f9c0c75ea02d629a217e11c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55079 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 diff --git a/assets/appx/SmallTile.png b/assets/appx/SmallTile.png deleted file mode 100644 index 91b41331245d33d2950b5408b3f29d566921c588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7572 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 F{|8hO437W+ diff --git a/assets/appx/Square150x150Logo.png b/assets/appx/Square150x150Logo.png index 730eb9463dd7c104a1da620d12b0957248caa850..007497bb0baa2b3d4ee5ddfdb32711114b8ce4ce 100644 GIT binary patch literal 6414 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 LaK7HmC-y%8D1;ah literal 23097 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%0DE=Nv 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 TDQZ#F00000NkvXXu0mjfQ)R7q literal 4112 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
-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 P00000NkvXXu0mjfMUPJD literal 42634 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 diff --git a/assets/appx/Wide310x150Logo.png b/assets/appx/Wide310x150Logo.png index fbe0e56b34f74635cb879d546f3cea84b56816ba..4ffec3997b5afa748ab666acea3bb1139a5206ab 100644 GIT binary patch literal 7605 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 =^!9g%ZEo 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 I;)X&03nns+TL1t6 diff --git a/package.json b/package.json index 08617900..cf93c684 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { "name": "antares", "productName": "Antares", - "version": "0.3.8", - "description": "A cross-platform easy to use SQL client.", + "version": "0.4.3", + "description": "A modern, fast and productivity driven SQL client with a focus in UX.", "license": "MIT", "repository": "https://github.com/Fabio286/antares.git", "scripts": { @@ -14,11 +14,11 @@ "build": "cross-env NODE_ENV=production npm run compile", "build:local": "npm run build && electron-builder", "build:appx": "npm run build:local -- --win appx", - "rebuild:electron": "npm run postinstall && electron-rebuild", + "rebuild:electron": "npm run postinstall", "release": "standard-version", "release:pre": "npm run release -- --prerelease alpha", "postinstall": "electron-builder install-app-deps", - "test": "npm run lint", + "test": "npm run compile && node tests/app.spec.js", "lint": "eslint . --ext .js,.vue && stylelint \"./src/**/*.{css,scss,sass,vue}\"", "lint:fix": "eslint . --ext .js,.vue --fix && stylelint \"./src/**/*.{css,scss,sass,vue}\" --fix", "contributors:add": "all-contributors add", @@ -30,6 +30,7 @@ "appId": "com.fabio286.antares", "artifactName": "${productName}-${version}-${os}_${arch}.${ext}", "asar": true, + "buildDependenciesFromSource": true, "directories": { "output": "build", "buildResources": "assets" @@ -50,7 +51,8 @@ "target": { "target": "default", "arch": [ - "x64" + "x64", + "arm64" ] } }, @@ -79,7 +81,9 @@ "artifactName": "${productName}-${version}-portable.exe" }, "appx": { - "displayName": "Antares SQL Client", + "displayName": "Antares SQL", + "backgroundColor": "transparent", + "showNameOnTiles": true, "identityName": "62514FabioDiStasio.AntaresSQLClient", "publisher": "CN=1A2729ED-865C-41D2-9038-39AE2A63AA52", "applicationId": "FabioDiStasio.AntaresSQLClient" @@ -102,12 +106,17 @@ "dependencies": { "@electron/remote": "^2.0.1", "@mdi/font": "^6.1.95", + "@turf/helpers": "^6.5.0", + "@vscode/vscode-languagedetection": "^1.0.21", "ace-builds": "^1.4.13", + "better-sqlite3": "^7.4.4", "electron-log": "^4.4.1", "electron-store": "^8.0.1", - "electron-updater": "^4.3.9", + "electron-updater": "^4.6.1", + "electron-window-state": "^5.0.3", "faker": "^5.5.3", - "marked": "^3.0.4", + "leaflet": "^1.7.1", + "marked": "^4.0.0", "moment": "^2.29.1", "mysql2": "^2.3.2", "pg": "^8.7.1", @@ -130,23 +139,23 @@ "clean-webpack-plugin": "^4.0.0", "cross-env": "^7.0.2", "css-loader": "^6.5.0", - "electron": "^15.3.0", - "electron-builder": "^22.13.1", + "electron": "^17.0.1", + "electron-builder": "^22.14.11", "electron-devtools-installer": "^3.2.0", - "electron-rebuild": "^3.2.3", "eslint": "^7.32.0", "eslint-config-standard": "^16.0.3", "eslint-plugin-import": "^2.24.2", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-promise": "^5.1.0", - "eslint-plugin-vue": "^7.18.0", + "eslint-plugin-promise": "^5.2.0", + "eslint-plugin-vue": "^8.0.3", "file-loader": "^6.2.0", "html-webpack-plugin": "^5.5.0", - "mini-css-extract-plugin": "^2.4.3", + "mini-css-extract-plugin": "~2.4.5", "node-loader": "^2.0.0", + "playwright": "^1.18.1", "progress-webpack-plugin": "^1.0.12", "sass": "^1.42.1", - "sass-loader": "^10.2.0", + "sass-loader": "^12.3.0", "standard-version": "^9.3.1", "style-loader": "^3.3.1", "stylelint": "^13.13.1", @@ -158,6 +167,6 @@ "vue-template-compiler": "^2.6.14", "webpack": "^5.60.0", "webpack-cli": "^4.9.1", - "webpack-dev-server": "^3.11.2" + "webpack-dev-server": "^4.4.0" } -} \ No newline at end of file +} diff --git a/scripts/devRunner.js b/scripts/devRunner.js index bfbea89d..ed3eff40 100644 --- a/scripts/devRunner.js +++ b/scripts/devRunner.js @@ -113,14 +113,15 @@ function startRenderer (callback) { }); const server = new WebpackDevServer(compiler, { - contentBase: path.join(__dirname, '../'), hot: true, - noInfo: true, - overlay: true, - clientLogLevel: 'warning' + port: 9080, + client: { + overlay: true, + logging: 'warn' + } }); - server.listen(9080, '', err => { + server.startCallback(err => { if (err) console.error(chalk.red(err)); callback(); diff --git a/src/common/FakerMethods.js b/src/common/FakerMethods.js index fe7c7ec4..e401fa11 100644 --- a/src/common/FakerMethods.js +++ b/src/common/FakerMethods.js @@ -134,7 +134,7 @@ export default class { { name: 'phoneNumberFormat', group: 'phone', types: ['string'] }, { name: 'phoneFormats', group: 'phone', types: ['string'] }, - { name: 'number', group: 'random', types: ['string', 'number'], params: ['min', 'max'] }, + { name: 'number', group: 'datatype', types: ['string', 'number'], params: ['min', 'max'] }, { name: 'float', group: 'random', types: ['string', 'float'], params: ['min', 'max'] }, { name: 'arrayElement', group: 'random', types: ['string'] }, { name: 'arrayElements', group: 'random', types: ['string'] }, diff --git a/src/common/customizations/defaults.js b/src/common/customizations/defaults.js index 1cc0fe47..ad5788df 100644 --- a/src/common/customizations/defaults.js +++ b/src/common/customizations/defaults.js @@ -8,6 +8,10 @@ module.exports = { collations: false, engines: false, connectionSchema: false, + sslConnection: false, + sshConnection: false, + fileConnection: false, + cancelQueries: false, // Tools processesList: false, usersManagement: false, @@ -33,7 +37,12 @@ module.exports = { schedulerAdd: false, databaseEdit: false, schemaEdit: false, + schemaDrop: false, + schemaExport: false, tableSettings: false, + tableOptions: false, + tableArray: false, + tableRealCount: false, viewSettings: false, triggerSettings: false, triggerFunctionSettings: false, @@ -45,14 +54,13 @@ module.exports = { sortableFields: false, unsigned: false, nullable: false, + nullablePrimary: false, zerofill: false, - tableOptions: false, autoIncrement: false, comment: false, collation: false, definer: false, onUpdate: false, - tableArray: false, viewAlgorithm: false, viewSqlSecurity: false, viewUpdateOption: false, @@ -72,8 +80,10 @@ module.exports = { triggerTableInName: false, triggerUpdateColumns: false, triggerOnlyRename: false, + triggerEnableDisable: false, triggerFunctionSql: false, triggerFunctionlanguages: false, parametersLength: false, - languages: false + languages: false, + readOnlyMode: false }; diff --git a/src/common/customizations/index.js b/src/common/customizations/index.js index 304889a4..931e18f2 100644 --- a/src/common/customizations/index.js +++ b/src/common/customizations/index.js @@ -1,5 +1,6 @@ module.exports = { maria: require('./mysql'), mysql: require('./mysql'), - pg: require('./postgresql') + pg: require('./postgresql'), + sqlite: require('./sqlite') }; diff --git a/src/common/customizations/mysql.js b/src/common/customizations/mysql.js index 79fae6bc..d037d26c 100644 --- a/src/common/customizations/mysql.js +++ b/src/common/customizations/mysql.js @@ -10,6 +10,9 @@ module.exports = { connectionSchema: true, collations: true, engines: true, + sslConnection: true, + sshConnection: true, + cancelQueries: true, // Tools processesList: true, // Structure @@ -30,6 +33,7 @@ module.exports = { functionAdd: true, schedulerAdd: true, schemaEdit: true, + schemaDrop: true, schemaExport: true, tableSettings: true, viewSettings: true, @@ -60,5 +64,6 @@ module.exports = { functionDeterministic: true, functionDataAccess: true, functionSql: 'BEGIN\r\n\r\nEND', - parametersLength: true + parametersLength: true, + readOnlyMode: true }; diff --git a/src/common/customizations/postgresql.js b/src/common/customizations/postgresql.js index 655a716b..3d827c11 100644 --- a/src/common/customizations/postgresql.js +++ b/src/common/customizations/postgresql.js @@ -8,9 +8,13 @@ module.exports = { defaultDatabase: 'postgres', // Core database: true, + sslConnection: true, + sshConnection: true, + cancelQueries: true, // Tools processesList: true, // Structure + schemas: true, tables: true, views: true, triggers: true, @@ -26,6 +30,7 @@ module.exports = { triggerFunctionAdd: true, routineAdd: true, functionAdd: true, + schemaDrop: true, databaseEdit: false, schemaExport: true, tableSettings: true, @@ -51,5 +56,7 @@ module.exports = { triggerMultipleEvents: true, triggerTableInName: true, triggerOnlyRename: false, - languages: ['sql', 'plpgsql', 'c', 'internal'] + triggerEnableDisable: true, + languages: ['sql', 'plpgsql', 'c', 'internal'], + readOnlyMode: true }; diff --git a/src/common/customizations/sqlite.js b/src/common/customizations/sqlite.js new file mode 100644 index 00000000..83c6cdb3 --- /dev/null +++ b/src/common/customizations/sqlite.js @@ -0,0 +1,27 @@ +module.exports = { + // Core + fileConnection: true, + // Structure + schemas: false, + tables: true, + views: true, + triggers: true, + // Settings + elementsWrapper: '"', + stringsWrapper: '\'', + tableAdd: true, + viewAdd: true, + triggerAdd: true, + schemaEdit: false, + tableSettings: true, + tableRealCount: true, + viewSettings: true, + triggerSettings: true, + indexes: true, + foreigns: true, + sortableFields: true, + nullable: true, + nullablePrimary: true, + triggerSql: 'BEGIN\r\n\r\nEND', + readOnlyMode: true +}; diff --git a/src/common/data-types/mysql.js b/src/common/data-types/mysql.js index 78e3d2c9..14b61229 100644 --- a/src/common/data-types/mysql.js +++ b/src/common/data-types/mysql.js @@ -66,6 +66,7 @@ module.exports = [ { name: 'DECIMAL', length: true, + scale: true, collation: false, unsigned: false, zerofill: false @@ -120,7 +121,7 @@ module.exports = [ { name: 'JSON', length: false, - collation: true, + collation: false, unsigned: false, zerofill: false } @@ -218,56 +219,56 @@ module.exports = [ types: [ { name: 'POINT', - length: true, + length: false, collation: false, unsigned: false, zerofill: false }, { name: 'LINESTRING', - length: true, + length: false, collation: false, unsigned: false, zerofill: false }, { name: 'POLYGON', - length: true, + length: false, collation: false, unsigned: false, zerofill: false }, { name: 'GEOMETRY', - length: true, + length: false, collation: false, unsigned: false, zerofill: false }, { name: 'MULTIPOINT', - length: true, + length: false, collation: false, unsigned: false, zerofill: false }, { name: 'MULTILINESTRING', - length: true, + length: false, collation: false, unsigned: false, zerofill: false }, { name: 'MULTIPOLYGON', - length: true, + length: false, collation: false, unsigned: false, zerofill: false }, { - name: 'GEOMETRYCOLLECTION', - length: true, + name: 'GEOMCOLLECTION', + length: false, collation: false, unsigned: false, zerofill: false diff --git a/src/common/data-types/postgresql.js b/src/common/data-types/postgresql.js index bfe9e50d..e666229b 100644 --- a/src/common/data-types/postgresql.js +++ b/src/common/data-types/postgresql.js @@ -22,11 +22,6 @@ module.exports = [ length: false, unsigned: true }, - { - name: 'NUMERIC', - length: true, - unsigned: true - }, { name: 'SMALLSERIAL', length: false, @@ -52,6 +47,12 @@ module.exports = [ length: false, unsigned: true }, + { + name: 'NUMERIC', + length: true, + unsigned: true, + scale: true + }, { name: 'DOUBLE PRECISION', length: false, diff --git a/src/common/data-types/sqlite.js b/src/common/data-types/sqlite.js new file mode 100644 index 00000000..c7ac6b32 --- /dev/null +++ b/src/common/data-types/sqlite.js @@ -0,0 +1,137 @@ +module.exports = [ + { + group: 'integer', + types: [ + { + name: 'INT', + length: true, + collation: false, + unsigned: true, + zerofill: true + }, + { + name: 'INTEGER', + length: true, + collation: false, + unsigned: true, + zerofill: true + }, + { + name: 'BIGINT', + length: true, + collation: false, + unsigned: true, + zerofill: true + }, + { + name: 'NUMERIC', + length: true, + collation: false, + unsigned: true, + zerofill: true + }, + { + name: 'BOOLEAN', + length: false, + collation: false, + unsigned: true, + zerofill: true + } + ] + }, + { + group: 'float', + types: [ + { + name: 'FLOAT', + length: true, + collation: false, + unsigned: false, + zerofill: false + }, + { + name: 'REAL', + length: true, + collation: false, + unsigned: false, + zerofill: false + } + ] + }, + { + group: 'string', + types: [ + { + name: 'CHAR', + length: true, + collation: true, + unsigned: false, + zerofill: false + }, + { + name: 'VARCHAR', + length: true, + collation: true, + unsigned: false, + zerofill: false + }, + { + name: 'TEXT', + length: true, + collation: true, + unsigned: false, + zerofill: false + } + ] + }, + { + group: 'binary', + types: [ + { + name: 'BLOB', + length: true, + collation: false, + unsigned: false, + zerofill: false + } + ] + }, + { + group: 'time', + types: [ + { + name: 'DATE', + length: false, + collation: false, + unsigned: false, + zerofill: false + }, + { + name: 'TIME', + length: true, + collation: false, + unsigned: false, + zerofill: false + }, + { + name: 'DATETIME', + length: true, + collation: false, + unsigned: false, + zerofill: false + } + ] + }, + { + group: 'other', + types: [ + { + name: 'NONE', + length: false, + collation: false, + unsigned: false, + zerofill: false + } + ] + } +]; diff --git a/src/common/fieldTypes.js b/src/common/fieldTypes.js index d3a8a1db..a7d3399f 100644 --- a/src/common/fieldTypes.js +++ b/src/common/fieldTypes.js @@ -8,7 +8,9 @@ export const TEXT = [ export const LONG_TEXT = [ 'TEXT', 'MEDIUMTEXT', - 'LONGTEXT' + 'LONGTEXT', + 'JSON', + 'VARBINARY' ]; export const ARRAY = [ @@ -82,3 +84,24 @@ export const BIT = [ 'BIT', 'BIT VARYING' ]; + +export const SPATIAL = [ + 'POINT', + 'LINESTRING', + 'POLYGON', + 'GEOMETRY', + 'MULTIPOINT', + 'MULTILINESTRING', + 'MULTIPOLYGON', + 'GEOMCOLLECTION', + 'GEOMETRYCOLLECTION' +]; + +// Used to check multi spatial fields only +export const IS_MULTI_SPATIAL = [ + 'MULTIPOINT', + 'MULTILINESTRING', + 'MULTIPOLYGON', + 'GEOMCOLLECTION', + 'GEOMETRYCOLLECTION' +]; diff --git a/src/common/index-types/sqlite.js b/src/common/index-types/sqlite.js new file mode 100644 index 00000000..edc2f2a3 --- /dev/null +++ b/src/common/index-types/sqlite.js @@ -0,0 +1,5 @@ +module.exports = [ + 'PRIMARY', + 'INDEX', + 'UNIQUE' +]; diff --git a/src/common/libs/getArrayDepth.js b/src/common/libs/getArrayDepth.js new file mode 100644 index 00000000..04e62e77 --- /dev/null +++ b/src/common/libs/getArrayDepth.js @@ -0,0 +1,10 @@ +/** + * + * @param {any[]} array + * @returns {number} + */ +export function getArrayDepth (array) { + return Array.isArray(array) + ? 1 + Math.max(0, ...array.map(getArrayDepth)) + : 0; +} diff --git a/src/main/ipc-handlers/connection.js b/src/main/ipc-handlers/connection.js index aa2c1378..c539f75a 100644 --- a/src/main/ipc-handlers/connection.js +++ b/src/main/ipc-handlers/connection.js @@ -9,12 +9,16 @@ export default connections => { port: +conn.port, user: conn.user, password: conn.password, - application_name: 'Antares SQL' + application_name: 'Antares SQL', + readonly: conn.readonly }; if (conn.database) params.database = conn.database; + if (conn.databasePath) + params.databasePath = conn.databasePath; + if (conn.ssl) { params.ssl = { key: conn.key ? fs.readFileSync(conn.key) : null, @@ -48,7 +52,7 @@ export default connections => { return { status: 'success' }; } catch (err) { - return { status: 'error', response: err }; + return { status: 'error', response: err.toString() }; } }); @@ -62,12 +66,16 @@ export default connections => { port: +conn.port, user: conn.user, password: conn.password, - application_name: 'Antares SQL' + application_name: 'Antares SQL', + readonly: conn.readonly }; if (conn.database) params.database = conn.database; + if (conn.databasePath) + params.databasePath = conn.databasePath; + if (conn.schema) params.schema = conn.schema; diff --git a/src/main/ipc-handlers/schedulers.js b/src/main/ipc-handlers/schedulers.js index 4133fbed..f270beb3 100644 --- a/src/main/ipc-handlers/schedulers.js +++ b/src/main/ipc-handlers/schedulers.js @@ -40,4 +40,17 @@ export default (connections) => { return { status: 'error', response: err.toString() }; } }); + + ipcMain.handle('toggle-scheduler', async (event, params) => { + try { + if (!params.enabled) + await connections[params.uid].enableEvent({ ...params }); + else + await connections[params.uid].disableEvent({ ...params }); + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); }; diff --git a/src/main/ipc-handlers/schema.js b/src/main/ipc-handlers/schema.js index c59d9e0f..f161a5ae 100644 --- a/src/main/ipc-handlers/schema.js +++ b/src/main/ipc-handlers/schema.js @@ -149,7 +149,7 @@ export default connections => { } }); - ipcMain.handle('raw-query', async (event, { uid, query, schema }) => { + ipcMain.handle('raw-query', async (event, { uid, query, schema, tabUid, autocommit }) => { if (!query) return; try { @@ -157,6 +157,8 @@ export default connections => { nest: true, details: true, schema, + tabUid, + autocommit, comments: false }); @@ -263,4 +265,51 @@ export default connections => { return { status: 'success', response: { willAbort } }; }); + ipcMain.handle('kill-tab-query', async (event, { uid, tabUid }) => { + if (!tabUid) return; + + try { + await connections[uid].killTabQuery(tabUid); + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); + + ipcMain.handle('commit-tab', async (event, { uid, tabUid }) => { + if (!tabUid) return; + + try { + await connections[uid].commitTab(tabUid); + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); + + ipcMain.handle('rollback-tab', async (event, { uid, tabUid }) => { + if (!tabUid) return; + + try { + await connections[uid].rollbackTab(tabUid); + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); + + ipcMain.handle('destroy-connection-to-commit', async (event, { uid, tabUid }) => { + if (!tabUid) return; + + try { + await connections[uid].destroyConnectionToCommit(tabUid); + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); }; diff --git a/src/main/ipc-handlers/tables.js b/src/main/ipc-handlers/tables.js index 47ef823f..7791aa5b 100644 --- a/src/main/ipc-handlers/tables.js +++ b/src/main/ipc-handlers/tables.js @@ -3,6 +3,7 @@ import faker from 'faker'; import moment from 'moment'; import { sqlEscaper } from 'common/libs/sqlEscaper'; import { TEXT, LONG_TEXT, ARRAY, TEXT_SEARCH, NUMBER, FLOAT, BLOB, BIT, DATE, DATETIME } from 'common/fieldTypes'; +import * as customizations from 'common/customizations'; import fs from 'fs'; export default (connections) => { @@ -84,12 +85,13 @@ export default (connections) => { }); ipcMain.handle('update-table-cell', async (event, params) => { - delete params.row._id; + delete params.row._antares_id; + const { stringsWrapper: sw } = customizations[connections[params.uid]._client]; try { // TODO: move to client classes let escapedParam; let reload = false; - const id = typeof params.id === 'number' ? params.id : `"${params.id}"`; + const id = typeof params.id === 'number' ? params.id : `${sw}${params.id}${sw}`; if ([...NUMBER, ...FLOAT].includes(params.type)) escapedParam = params.content; @@ -102,6 +104,9 @@ export default (connections) => { case 'pg': escapedParam = `'${params.content.replaceAll('\'', '\'\'')}'`; break; + case 'sqlite': + escapedParam = `'${params.content.replaceAll('\'', '\'\'')}'`; + break; } } else if (ARRAY.includes(params.type)) @@ -122,6 +127,10 @@ export default (connections) => { fileBlob = fs.readFileSync(params.content); escapedParam = `decode('${fileBlob.toString('hex')}', 'hex')`; break; + case 'sqlite': + fileBlob = fs.readFileSync(params.content); + escapedParam = `X'${fileBlob.toString('hex')}'`; + break; } reload = true; } @@ -134,6 +143,9 @@ export default (connections) => { case 'pg': escapedParam = 'decode(\'\', \'hex\')'; break; + case 'sqlite': + escapedParam = 'X\'\''; + break; } } } @@ -188,7 +200,7 @@ export default (connections) => { const fieldName = Object.keys(row)[0].includes('.') ? `${params.table}.${params.primary}` : params.primary; return typeof row[fieldName] === 'string' - ? `"${row[fieldName]}"` + ? `'${row[fieldName]}'` : row[fieldName]; }).join(','); diff --git a/src/main/ipc-handlers/triggers.js b/src/main/ipc-handlers/triggers.js index b7edaeab..89df9a15 100644 --- a/src/main/ipc-handlers/triggers.js +++ b/src/main/ipc-handlers/triggers.js @@ -40,4 +40,17 @@ export default (connections) => { return { status: 'error', response: err.toString() }; } }); + + ipcMain.handle('toggle-trigger', async (event, params) => { + try { + if (!params.enabled) + await connections[params.uid].enableTrigger(params); + else + await connections[params.uid].disableTrigger(params); + return { status: 'success' }; + } + catch (err) { + return { status: 'error', response: err.toString() }; + } + }); }; diff --git a/src/main/ipc-handlers/updates.js b/src/main/ipc-handlers/updates.js index ff72702e..19636b52 100644 --- a/src/main/ipc-handlers/updates.js +++ b/src/main/ipc-handlers/updates.js @@ -2,6 +2,7 @@ import { ipcMain } from 'electron'; import { autoUpdater } from 'electron-updater'; import Store from 'electron-store'; const persistentStore = new Store({ name: 'settings' }); +const isMacOS = process.platform === 'darwin'; let mainWindow; autoUpdater.allowPrerelease = persistentStore.get('allow_prerelease', true); @@ -11,6 +12,9 @@ export default () => { mainWindow = event; if (process.windowsStore || (process.platform === 'linux' && !process.env.APPIMAGE)) mainWindow.reply('no-auto-update'); + else if (isMacOS) { // Temporary solution on MacOS for unsigned app updates + autoUpdater.autoDownload = false; + } else { autoUpdater.checkForUpdatesAndNotify().catch(() => { mainWindow.reply('check-failed'); @@ -28,7 +32,10 @@ export default () => { }); autoUpdater.on('update-available', () => { - mainWindow.reply('update-available'); + if (isMacOS) + mainWindow.reply('link-to-download'); + else + mainWindow.reply('update-available'); }); autoUpdater.on('update-not-available', () => { diff --git a/src/main/libs/ClientsFactory.js b/src/main/libs/ClientsFactory.js index 54211908..6543eaff 100644 --- a/src/main/libs/ClientsFactory.js +++ b/src/main/libs/ClientsFactory.js @@ -1,6 +1,7 @@ 'use strict'; import { MySQLClient } from './clients/MySQLClient'; import { PostgreSQLClient } from './clients/PostgreSQLClient'; +import { SQLiteClient } from './clients/SQLiteClient'; const queryLogger = sql => { // Remove comments, newlines and multiple spaces @@ -37,6 +38,8 @@ export class ClientsFactory { return new MySQLClient(args); case 'pg': return new PostgreSQLClient(args); + case 'sqlite': + return new SQLiteClient(args); default: throw new Error(`Unknown database client: ${args.client}`); } diff --git a/src/main/libs/clients/MySQLClient.js b/src/main/libs/clients/MySQLClient.js index 1fce40f9..d31e1be6 100644 --- a/src/main/libs/clients/MySQLClient.js +++ b/src/main/libs/clients/MySQLClient.js @@ -9,6 +9,8 @@ export class MySQLClient extends AntaresCore { super(args); this._schema = null; + this._runningConnections = new Map(); + this._connectionsToCommit = new Map(); this.types = { 0: 'DECIMAL', @@ -100,9 +102,11 @@ export class MySQLClient extends AntaresCore { } /** + * + * @returns dbConfig * @memberof MySQLClient */ - async connect () { + async getDbConfig () { delete this._params.application_name; const dbConfig = { @@ -133,20 +137,17 @@ export class MySQLClient extends AntaresCore { } } + return dbConfig; + } + + /** + * @memberof MySQLClient + */ + async connect () { if (!this._poolSize) - this._connection = await mysql.createConnection(dbConfig); - else { - this._connection = mysql.createPool({ - ...dbConfig, - connectionLimit: this._poolSize, - typeCast: (field, next) => { - if (field.type === 'DATETIME') - return field.string(); - else - return next(); - } - }); - } + this._connection = await this.getConnection(); + else + this._connection = await this.getConnectionPool(); } /** @@ -157,6 +158,64 @@ export class MySQLClient extends AntaresCore { if (this._ssh) this._ssh.close(); } + async getConnection () { + const dbConfig = await this.getDbConfig(); + const connection = await mysql.createConnection({ + ...dbConfig, + typeCast: (field, next) => { + if (field.type === 'DATETIME') + return field.string(); + else + return next(); + } + }); + + // ANSI_QUOTES check + const [res] = await connection.query('SHOW GLOBAL VARIABLES LIKE \'%sql_mode%\''); + const sqlMode = res[0]?.Variable_name?.split(','); + const hasAnsiQuotes = sqlMode.includes('ANSI_QUOTES'); + + if (this._params.readonly) + await connection.query('SET SESSION TRANSACTION READ ONLY'); + + if (hasAnsiQuotes) + await connection.query(`SET SESSION sql_mode = "${sqlMode.filter(m => m !== 'ANSI_QUOTES').join(',')}"`); + + return connection; + } + + async getConnectionPool () { + const dbConfig = await this.getDbConfig(); + const connection = mysql.createPool({ + ...dbConfig, + connectionLimit: this._poolSize, + typeCast: (field, next) => { + if (field.type === 'DATETIME') + return field.string(); + else + return next(); + } + }); + + // ANSI_QUOTES check + const [res] = await connection.query('SHOW GLOBAL VARIABLES LIKE \'%sql_mode%\''); + const sqlMode = res[0]?.Variable_name?.split(','); + const hasAnsiQuotes = sqlMode.includes('ANSI_QUOTES'); + + if (hasAnsiQuotes) + await connection.query(`SET SESSION sql_mode = "${sqlMode.filter(m => m !== 'ANSI_QUOTES').join(',')}"`); + + connection.on('connection', conn => { + if (this._params.readonly) + conn.query('SET SESSION TRANSACTION READ ONLY'); + + if (hasAnsiQuotes) + conn.query(`SET SESSION sql_mode = "${sqlMode.filter(m => m !== 'ANSI_QUOTES').join(',')}"`); + }); + + return connection; + } + /** * Executes an USE query * @@ -187,6 +246,7 @@ export class MySQLClient extends AntaresCore { const tablesArr = []; const triggersArr = []; + let schemaSize = 0; for (const db of filteredDatabases) { if (!schemas.has(db.Database)) continue; @@ -224,6 +284,9 @@ export class MySQLClient extends AntaresCore { break; } + const tableSize = table.Data_length + table.Index_length; + schemaSize += tableSize; + return { name: table.Name, type: tableType, @@ -232,7 +295,7 @@ export class MySQLClient extends AntaresCore { updated: table.Update_time, engine: table.Engine, comment: table.Comment, - size: table.Data_length + table.Index_length, + size: tableSize, autoIncrement: table.Auto_increment, collation: table.Collation }; @@ -276,7 +339,7 @@ export class MySQLClient extends AntaresCore { body: scheduler.EVENT_BODY, starts: scheduler.STARTS, ends: scheduler.ENDS, - status: scheduler.STATUS, + enabled: scheduler.STATUS === 'ENABLED', executeAt: scheduler.EXECUTE_AT, intervalField: scheduler.INTERVAL_FIELD, intervalValue: scheduler.INTERVAL_VALUE, @@ -309,6 +372,7 @@ export class MySQLClient extends AntaresCore { return { name: db.Database, + size: schemaSize, tables: remappedTables, functions: remappedFunctions, procedures: remappedProcedures, @@ -319,6 +383,7 @@ export class MySQLClient extends AntaresCore { else { return { name: db.Database, + size: 0, tables: [], functions: [], procedures: [], @@ -360,7 +425,7 @@ export class MySQLClient extends AntaresCore { return acc; }, '') .replaceAll('\n', '') - .split(',') + .split(/,\s?(?![^(]*\))/) .map(f => { try { const fieldArr = f.trim().split(' '); @@ -400,18 +465,25 @@ export class MySQLClient extends AntaresCore { return rows.map(field => { let numLength = field.COLUMN_TYPE.match(/int\(([^)]+)\)/); - numLength = numLength ? +numLength.pop() : null; + numLength = numLength ? +numLength.pop() : field.NUMERIC_PRECISION || null; const enumValues = /(enum|set)/.test(field.COLUMN_TYPE) ? field.COLUMN_TYPE.match(/\(([^)]+)\)/)[0].slice(1, -1) : null; + const defaultValue = (remappedFields && remappedFields[field.COLUMN_NAME]) + ? remappedFields[field.COLUMN_NAME].default + : field.COLUMN_DEFAULT; + return { name: field.COLUMN_NAME, key: field.COLUMN_KEY.toLowerCase(), - type: remappedFields ? remappedFields[field.COLUMN_NAME].type : field.DATA_TYPE, + type: (remappedFields && remappedFields[field.COLUMN_NAME]) + ? remappedFields[field.COLUMN_NAME].type + : field.DATA_TYPE.toUpperCase(), schema: field.TABLE_SCHEMA, table: field.TABLE_NAME, numPrecision: field.NUMERIC_PRECISION, + numScale: field.NUMERIC_SCALE, numLength, enumValues, datePrecision: field.DATETIME_PRECISION, @@ -420,11 +492,13 @@ export class MySQLClient extends AntaresCore { unsigned: field.COLUMN_TYPE.includes('unsigned'), zerofill: field.COLUMN_TYPE.includes('zerofill'), order: field.ORDINAL_POSITION, - default: remappedFields ? remappedFields[field.COLUMN_NAME].default : field.COLUMN_DEFAULT, + default: defaultValue, charset: field.CHARACTER_SET_NAME, collation: field.COLLATION_NAME, autoIncrement: field.EXTRA.includes('auto_increment'), - onUpdate: field.EXTRA.toLowerCase().includes('on update') ? field.EXTRA.replace('on update', '') : '', + onUpdate: field.EXTRA.toLowerCase().includes('on update') + ? field.EXTRA.substr(field.EXTRA.indexOf('on update') + 9, field.EXTRA.length).trim() + : '', comment: field.COLUMN_COMMENT }; }); @@ -565,7 +639,7 @@ export class MySQLClient extends AntaresCore { /** * CREATE DATABASE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async createSchema (params) { @@ -575,7 +649,7 @@ export class MySQLClient extends AntaresCore { /** * ALTER DATABASE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async alterSchema (params) { @@ -585,7 +659,7 @@ export class MySQLClient extends AntaresCore { /** * DROP DATABASE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async dropSchema (params) { @@ -625,7 +699,7 @@ export class MySQLClient extends AntaresCore { /** * DROP VIEW * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async dropView (params) { @@ -636,7 +710,7 @@ export class MySQLClient extends AntaresCore { /** * ALTER VIEW * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async alterView (params) { @@ -657,7 +731,7 @@ export class MySQLClient extends AntaresCore { /** * CREATE VIEW * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async createView (params) { @@ -690,7 +764,7 @@ export class MySQLClient extends AntaresCore { /** * DROP TRIGGER * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async dropTrigger (params) { @@ -701,7 +775,7 @@ export class MySQLClient extends AntaresCore { /** * ALTER TRIGGER * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async alterTrigger (params) { @@ -723,7 +797,7 @@ export class MySQLClient extends AntaresCore { /** * CREATE TRIGGER * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async createTrigger (params) { @@ -797,7 +871,7 @@ export class MySQLClient extends AntaresCore { /** * DROP PROCEDURE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async dropRoutine (params) { @@ -808,7 +882,7 @@ export class MySQLClient extends AntaresCore { /** * ALTER PROCEDURE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async alterRoutine (params) { @@ -830,7 +904,7 @@ export class MySQLClient extends AntaresCore { /** * CREATE PROCEDURE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async createRoutine (params) { @@ -924,7 +998,7 @@ export class MySQLClient extends AntaresCore { /** * DROP FUNCTION * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async dropFunction (params) { @@ -935,7 +1009,7 @@ export class MySQLClient extends AntaresCore { /** * ALTER FUNCTION * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async alterFunction (params) { @@ -957,7 +1031,7 @@ export class MySQLClient extends AntaresCore { /** * CREATE FUNCTION * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async createFunction (params) { @@ -1018,7 +1092,7 @@ export class MySQLClient extends AntaresCore { /** * DROP EVENT * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async dropEvent (params) { @@ -1029,7 +1103,7 @@ export class MySQLClient extends AntaresCore { /** * ALTER EVENT * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async alterEvent (params) { @@ -1055,7 +1129,7 @@ export class MySQLClient extends AntaresCore { /** * CREATE EVENT * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async createEvent (params) { @@ -1072,6 +1146,16 @@ export class MySQLClient extends AntaresCore { return await this.raw(sql, { split: false }); } + async enableEvent ({ schema, scheduler }) { + const sql = `ALTER EVENT \`${schema}\`.\`${scheduler}\` ENABLE`; + return await this.raw(sql, { split: false }); + } + + async disableEvent ({ schema, scheduler }) { + const sql = `ALTER EVENT \`${schema}\`.\`${scheduler}\` DISABLE`; + return await this.raw(sql, { split: false }); + } + /** * SHOW COLLATION * @@ -1111,6 +1195,26 @@ export class MySQLClient extends AntaresCore { }); } + /** + * SHOW VARIABLES LIKE %variable% + * + * @param {String} variable + * @param {'global'|'session'|null} level + * @returns {Object} variable + * @memberof MySQLClient + */ + async getVariable (variable, level) { + const sql = `SHOW${level ? ' ' + level.toUpperCase() : ''} VARIABLES LIKE '%${variable}%'`; + const results = await this.raw(sql); + + if (results.rows.length) { + return { + name: results.rows[0].Variable_name, + value: results.rows[0].Value + }; + } + } + /** * SHOW ENGINES * @@ -1182,14 +1286,60 @@ export class MySQLClient extends AntaresCore { }); } + /** + * + * @param {number} id + * @returns {Promise} + */ async killProcess (id) { return await this.raw(`KILL ${id}`); } + /** + * + * @param {string} tabUid + * @returns {Promise} + */ + async killTabQuery (tabUid) { + const id = this._runningConnections.get(tabUid); + if (id) + return await this.killProcess(id); + } + + /** + * + * @param {string} tabUid + * @returns {Promise} + */ + async commitTab (tabUid) { + const connection = this._connectionsToCommit.get(tabUid); + if (connection) + return await connection.query('COMMIT'); + } + + /** + * + * @param {string} tabUid + * @returns {Promise} + */ + async rollbackTab (tabUid) { + const connection = this._connectionsToCommit.get(tabUid); + if (connection) + return await connection.query('ROLLBACK'); + } + + destroyConnectionToCommit (tabUid) { + const connection = this._connectionsToCommit.get(tabUid); + if (connection) { + connection.destroy(); + this._connectionsToCommit.delete(tabUid); + } + } + /** * CREATE TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async createTable (params) { @@ -1212,7 +1362,7 @@ export class MySQLClient extends AntaresCore { const length = typeInfo.length ? field.enumValues || field.numLength || field.charLength || field.datePrecision : false; newColumns.push(`\`${field.name}\` - ${field.type.toUpperCase()}${length ? `(${length})` : ''} + ${field.type.toUpperCase()}${length ? `(${length}${field.numScale ? `,${field.numScale}` : ''})` : ''} ${field.unsigned ? 'UNSIGNED' : ''} ${field.zerofill ? 'ZEROFILL' : ''} ${field.nullable ? 'NULL' : 'NOT NULL'} @@ -1251,7 +1401,7 @@ export class MySQLClient extends AntaresCore { /** * ALTER TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async alterTable (params) { @@ -1281,7 +1431,7 @@ export class MySQLClient extends AntaresCore { const length = typeInfo.length ? addition.enumValues || addition.numLength || addition.charLength || addition.datePrecision : false; alterColumns.push(`ADD COLUMN \`${addition.name}\` - ${addition.type.toUpperCase()}${length ? `(${length})` : ''} + ${addition.type.toUpperCase()}${length ? `(${length}${addition.numScale ? `,${addition.numScale}` : ''})` : ''} ${addition.unsigned ? 'UNSIGNED' : ''} ${addition.zerofill ? 'ZEROFILL' : ''} ${addition.nullable ? 'NULL' : 'NOT NULL'} @@ -1319,7 +1469,7 @@ export class MySQLClient extends AntaresCore { const length = typeInfo.length ? change.enumValues || change.numLength || change.charLength || change.datePrecision : false; alterColumns.push(`CHANGE COLUMN \`${change.orgName}\` \`${change.name}\` - ${change.type.toUpperCase()}${length ? `(${length})` : ''} + ${change.type.toUpperCase()}${length ? `(${length}${change.numScale ? `,${change.numScale}` : ''})` : ''} ${change.unsigned ? 'UNSIGNED' : ''} ${change.zerofill ? 'ZEROFILL' : ''} ${change.nullable ? 'NULL' : 'NOT NULL'} @@ -1386,7 +1536,7 @@ export class MySQLClient extends AntaresCore { /** * DUPLICATE TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async duplicateTable (params) { @@ -1397,7 +1547,7 @@ export class MySQLClient extends AntaresCore { /** * TRUNCATE TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async truncateTable (params) { @@ -1408,7 +1558,7 @@ export class MySQLClient extends AntaresCore { /** * DROP TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async dropTable (params) { @@ -1490,6 +1640,7 @@ export class MySQLClient extends AntaresCore { details: false, split: true, comments: true, + autocommit: true, ...args }; @@ -1504,8 +1655,24 @@ export class MySQLClient extends AntaresCore { .filter(Boolean) .map(q => q.trim()) : [sql]; + + let connection; const isPool = typeof this._connection.getConnection === 'function'; - const connection = isPool ? await this._connection.getConnection() : this._connection; + + if (!args.autocommit && args.tabUid) { // autocommit OFF + if (this._connectionsToCommit.has(args.tabUid)) + connection = this._connectionsToCommit.get(args.tabUid); + else { + connection = await this.getConnection(); + await connection.query('SET SESSION autocommit=0'); + this._connectionsToCommit.set(args.tabUid, connection); + } + } + else// autocommit ON + connection = isPool ? await this._connection.getConnection() : this._connection; + + if (args.tabUid && isPool) + this._runningConnections.set(args.tabUid, connection.connection.connectionId); if (args.schema) await connection.query(`USE \`${args.schema}\``); @@ -1567,7 +1734,10 @@ export class MySQLClient extends AntaresCore { }); } catch (err) { - if (isPool) connection.release(); + if (isPool && args.autocommit) { + connection.release(); + this._runningConnections.delete(args.tabUid); + } reject(err); } @@ -1576,7 +1746,10 @@ export class MySQLClient extends AntaresCore { keysArr = keysArr ? [...keysArr, ...response] : response; } catch (err) { - if (isPool) connection.release(); + if (isPool && args.autocommit) { + connection.release(); + this._runningConnections.delete(args.tabUid); + } reject(err); } } @@ -1591,7 +1764,10 @@ export class MySQLClient extends AntaresCore { keys: keysArr }); }).catch((err) => { - if (isPool) connection.release(); + if (isPool && args.autocommit) { + connection.release(); + this._runningConnections.delete(args.tabUid); + } reject(err); }); }); @@ -1599,7 +1775,10 @@ export class MySQLClient extends AntaresCore { resultsArr.push({ rows, report, fields, keys, duration }); } - if (isPool) connection.release(); + if (isPool && args.autocommit) { + connection.release(); + this._runningConnections.delete(args.tabUid); + } return resultsArr.length === 1 ? resultsArr[0] : resultsArr; } diff --git a/src/main/libs/clients/PostgreSQLClient.js b/src/main/libs/clients/PostgreSQLClient.js index 7d9125e7..af9a4a56 100644 --- a/src/main/libs/clients/PostgreSQLClient.js +++ b/src/main/libs/clients/PostgreSQLClient.js @@ -9,6 +9,7 @@ function pgToString (value) { return value.toString(); } +types.setTypeParser(20, a => parseInt(a));// bigint string to number types.setTypeParser(1082, pgToString); // date types.setTypeParser(1083, pgToString); // time types.setTypeParser(1114, pgToString); // timestamp @@ -20,6 +21,8 @@ export class PostgreSQLClient extends AntaresCore { super(args); this._schema = null; + this._runningConnections = new Map(); + this._connectionsToCommit = new Map(); this.types = {}; for (const key in types.builtins) @@ -69,9 +72,11 @@ export class PostgreSQLClient extends AntaresCore { } /** + * + * @returns dbConfig * @memberof PostgreSQLClient */ - async connect () { + async getDbConfig () { const dbConfig = { host: this._params.host, port: this._params.port, @@ -100,15 +105,43 @@ export class PostgreSQLClient extends AntaresCore { } } - if (!this._poolSize) { - const client = new Client(dbConfig); - await client.connect(); - this._connection = client; - } - else { - const pool = new Pool({ ...dbConfig, max: this._poolSize }); - this._connection = pool; + return dbConfig; + } + + /** + * @memberof PostgreSQLClient + */ + async connect () { + if (!this._poolSize) + this._connection = await this.getConnection(); + else + this._connection = await this.getConnectionPool(); + } + + async getConnection () { + const dbConfig = await this.getDbConfig(); + const client = new Client(dbConfig); + await client.connect(); + const connection = client; + + if (this._params.readonly) + await connection.query('SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY'); + + return connection; + } + + async getConnectionPool () { + const dbConfig = await this.getDbConfig(); + const pool = new Pool({ ...dbConfig, max: this._poolSize }); + const connection = pool; + + if (this._params.readonly) { + connection.on('connect', conn => { + conn.query('SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY'); + }); } + + return connection; } /** @@ -120,15 +153,23 @@ export class PostgreSQLClient extends AntaresCore { } /** - * Executes an "USE" query + * Executes an 'SET search_path TO "${schema}"' query * * @param {String} schema + * @param {Object?} connection optional * @memberof PostgreSQLClient */ - use (schema) { + use (schema, connection) { this._schema = schema; - if (schema) - return this.raw(`SET search_path TO "${schema}"`); + + if (schema) { + const sql = `SET search_path TO "${schema}"`; + + if (connection === undefined) + return this.raw(sql); + else + return connection.query(sql); + } } /** @@ -143,6 +184,7 @@ export class PostgreSQLClient extends AntaresCore { const tablesArr = []; const triggersArr = []; + let schemaSize = 0; for (const db of databases) { if (!schemas.has(db.database)) continue; @@ -168,19 +210,20 @@ export class PostgreSQLClient extends AntaresCore { } let { rows: triggers } = await this.raw(` - SELECT event_object_schema AS table_schema, - event_object_table AS table_name, - trigger_schema, - trigger_name, - string_agg(event_manipulation, ',') AS event, - action_timing AS activation, - action_condition AS condition, - action_statement AS definition - FROM information_schema.triggers + SELECT + pg_class.relname AS table_name, + pg_trigger.tgname AS trigger_name, + pg_namespace.nspname AS trigger_schema, + (pg_trigger.tgenabled != 'D')::bool AS enabled + FROM pg_trigger + JOIN pg_class ON pg_trigger.tgrelid = pg_class.oid + JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace + JOIN information_schema.triggers ON information_schema.triggers.trigger_schema = pg_namespace.nspname + AND information_schema.triggers.event_object_table = pg_class.relname + AND information_schema.triggers.trigger_name = pg_trigger.tgname WHERE trigger_schema = '${db.database}' - GROUP BY 1,2,3,4,6,7,8 - ORDER BY table_schema, - table_name + GROUP BY 1, 2, 3, 4 + ORDER BY table_name `); if (triggers.length) { @@ -196,11 +239,14 @@ export class PostgreSQLClient extends AntaresCore { if (schemas.has(db.database)) { // TABLES const remappedTables = tablesArr.filter(table => table.Db === db.database).map(table => { + const tableSize = +table.data_length + table.index_length; + schemaSize += tableSize; + return { name: table.table_name, type: table.table_type === 'VIEW' ? 'view' : 'table', rows: table.reltuples, - size: +table.data_length + +table.index_length, + size: tableSize, collation: table.Collation, comment: table.comment, engine: '' @@ -239,17 +285,16 @@ export class PostgreSQLClient extends AntaresCore { return { name: `${trigger.table_name}.${trigger.trigger_name}`, orgName: trigger.trigger_name, - timing: trigger.activation, definer: '', - definition: trigger.definition, - event: trigger.event, table: trigger.table_name, - sqlMode: '' + sqlMode: '', + enabled: trigger.enabled }; }); return { name: db.database, + size: schemaSize, tables: remappedTables, functions: remappedFunctions, procedures: remappedProcedures, @@ -261,6 +306,7 @@ export class PostgreSQLClient extends AntaresCore { else { return { name: db.database, + size: 0, tables: [], functions: [], procedures: [], @@ -302,6 +348,7 @@ export class PostgreSQLClient extends AntaresCore { isArray, schema: field.table_schema, table: field.table_name, + numScale: field.numeric_scale, numPrecision: field.numeric_precision, datePrecision: field.datetime_precision, charLength: field.character_maximum_length, @@ -500,7 +547,7 @@ export class PostgreSQLClient extends AntaresCore { /** * CREATE SCHEMA * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async createSchema (params) { @@ -510,7 +557,7 @@ export class PostgreSQLClient extends AntaresCore { /** * ALTER DATABASE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async alterSchema (params) { @@ -520,7 +567,7 @@ export class PostgreSQLClient extends AntaresCore { /** * DROP DATABASE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof MySQLClient */ async dropSchema (params) { @@ -552,7 +599,7 @@ export class PostgreSQLClient extends AntaresCore { /** * DROP VIEW * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async dropView (params) { @@ -563,7 +610,7 @@ export class PostgreSQLClient extends AntaresCore { /** * ALTER VIEW * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async alterView (params) { @@ -579,7 +626,7 @@ export class PostgreSQLClient extends AntaresCore { /** * CREATE VIEW * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async createView (params) { @@ -597,19 +644,25 @@ export class PostgreSQLClient extends AntaresCore { const [table, triggerName] = trigger.split('.'); const results = await this.raw(` - SELECT event_object_schema AS table_schema, - event_object_table AS table_name, - trigger_schema, - trigger_name, - string_agg(event_manipulation, ',') AS event, + SELECT + information_schema.triggers.event_object_schema AS table_schema, + information_schema.triggers.event_object_table AS table_name, + information_schema.triggers.trigger_schema, + information_schema.triggers.trigger_name, + string_agg(event_manipulation, ',') AS EVENT, action_timing AS activation, action_condition AS condition, - action_statement AS definition - FROM information_schema.triggers + action_statement AS definition, + (pg_trigger.tgenabled != 'D')::bool AS enabled + FROM pg_trigger + JOIN pg_class ON pg_trigger.tgrelid = pg_class.oid + JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace + JOIN information_schema.triggers ON pg_namespace.nspname = information_schema.triggers.trigger_schema + AND pg_class.relname = information_schema.triggers.event_object_table WHERE trigger_schema = '${schema}' AND trigger_name = '${triggerName}' AND event_object_table = '${table}' - GROUP BY 1,2,3,4,6,7,8 + GROUP BY 1,2,3,4,6,7,8,9 ORDER BY table_schema, table_name `); @@ -619,7 +672,7 @@ export class PostgreSQLClient extends AntaresCore { sql: row.definition, name: row.trigger_name, table: row.table_name, - event: row.event.split(','), + event: [...new Set(row.event.split(','))], activation: row.activation }; })[0]; @@ -628,7 +681,7 @@ export class PostgreSQLClient extends AntaresCore { /** * DROP TRIGGER * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async dropTrigger (params) { @@ -640,7 +693,7 @@ export class PostgreSQLClient extends AntaresCore { /** * ALTER TRIGGER * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async alterTrigger (params) { @@ -662,7 +715,7 @@ export class PostgreSQLClient extends AntaresCore { /** * CREATE TRIGGER * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async createTrigger (params) { @@ -671,6 +724,18 @@ export class PostgreSQLClient extends AntaresCore { return await this.raw(sql, { split: false }); } + async enableTrigger ({ schema, trigger }) { + const [table, triggerName] = trigger.split('.'); + const sql = `ALTER TABLE "${schema}"."${table}" ENABLE TRIGGER "${triggerName}"`; + return await this.raw(sql, { split: false }); + } + + async disableTrigger ({ schema, trigger }) { + const [table, triggerName] = trigger.split('.'); + const sql = `ALTER TABLE "${schema}"."${table}" DISABLE TRIGGER "${triggerName}"`; + return await this.raw(sql, { split: false }); + } + /** * SHOW CREATE PROCEDURE * @@ -1055,14 +1120,64 @@ export class PostgreSQLClient extends AntaresCore { }); } + /** + * + * @param {number} id + * @returns {Promise} + */ async killProcess (id) { return await this.raw(`SELECT pg_terminate_backend(${id})`); } + /** + * + * @param {string} tabUid + * @returns {Promise} + */ + async killTabQuery (tabUid) { + const id = this._runningConnections.get(tabUid); + if (id) + return await this.raw(`SELECT pg_cancel_backend(${id})`); + } + + /** + * + * @param {string} tabUid + * @returns {Promise} + */ + async commitTab (tabUid) { + const connection = this._connectionsToCommit.get(tabUid); + if (connection) { + await connection.query('COMMIT'); + return this.destroyConnectionToCommit(tabUid); + } + } + + /** + * + * @param {string} tabUid + * @returns {Promise} + */ + async rollbackTab (tabUid) { + const connection = this._connectionsToCommit.get(tabUid); + if (connection) { + await connection.query('ROLLBACK'); + return this.destroyConnectionToCommit(tabUid); + } + } + + destroyConnectionToCommit (tabUid) { + const connection = this._connectionsToCommit.get(tabUid); + if (connection) { + connection.end(); + this._connectionsToCommit.delete(tabUid); + } + } + /** * CREATE TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async createTable (params) { @@ -1086,7 +1201,7 @@ export class PostgreSQLClient extends AntaresCore { const length = typeInfo.length ? field.enumValues || field.numLength || field.charLength || field.datePrecision : false; newColumns.push(`"${field.name}" - ${field.type.toUpperCase()}${length ? `(${length})` : ''} + ${field.type.toUpperCase()}${length ? `(${length}${field.numScale !== null ? `,${field.numScale}` : ''})` : ''} ${field.unsigned ? 'UNSIGNED' : ''} ${field.zerofill ? 'ZEROFILL' : ''} ${field.nullable ? 'NULL' : 'NOT NULL'} @@ -1120,7 +1235,7 @@ export class PostgreSQLClient extends AntaresCore { /** * ALTER TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async alterTable (params) { @@ -1150,7 +1265,7 @@ export class PostgreSQLClient extends AntaresCore { const length = typeInfo.length ? addition.numLength || addition.charLength || addition.datePrecision : false; alterColumns.push(`ADD COLUMN "${addition.name}" - ${addition.type.toUpperCase()}${length ? `(${length})` : ''}${addition.isArray ? '[]' : ''} + ${addition.type.toUpperCase()}${length ? `(${length}${addition.numScale !== null ? `,${addition.numScale}` : ''})` : ''}${addition.isArray ? '[]' : ''} ${addition.unsigned ? 'UNSIGNED' : ''} ${addition.zerofill ? 'ZEROFILL' : ''} ${addition.nullable ? 'NULL' : 'NOT NULL'} @@ -1196,7 +1311,7 @@ export class PostgreSQLClient extends AntaresCore { localType = change.type.toLowerCase(); } - alterColumns.push(`ALTER COLUMN "${change.name}" TYPE ${localType}${length ? `(${length})` : ''}${change.isArray ? '[]' : ''} USING "${change.name}"::${localType}`); + alterColumns.push(`ALTER COLUMN "${change.name}" TYPE ${localType}${length ? `(${length}${change.numScale ? `,${change.numScale}` : ''})` : ''}${change.isArray ? '[]' : ''} USING "${change.name}"::${localType}`); alterColumns.push(`ALTER COLUMN "${change.name}" ${change.nullable ? 'DROP NOT NULL' : 'SET NOT NULL'}`); alterColumns.push(`ALTER COLUMN "${change.name}" ${change.default ? `SET DEFAULT ${change.default}` : 'DROP DEFAULT'}`); @@ -1266,7 +1381,7 @@ export class PostgreSQLClient extends AntaresCore { /** * DUPLICATE TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async duplicateTable (params) { @@ -1277,7 +1392,7 @@ export class PostgreSQLClient extends AntaresCore { /** * TRUNCATE TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async truncateTable (params) { @@ -1288,7 +1403,7 @@ export class PostgreSQLClient extends AntaresCore { /** * DROP TABLE * - * @returns {Array.} parameters + * @returns {Promise} * @memberof PostgreSQLClient */ async dropTable (params) { @@ -1363,17 +1478,17 @@ export class PostgreSQLClient extends AntaresCore { * @memberof PostgreSQLClient */ async raw (sql, args) { + if (process.env.NODE_ENV === 'development') this._logger(sql);// TODO: replace BLOB content with a placeholder + args = { nest: false, details: false, split: true, comments: true, + autocommit: true, ...args }; - if (args.schema && args.schema !== 'public') - await this.use(args.schema); - if (!args.comments) sql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '');// Remove comments @@ -1385,7 +1500,26 @@ export class PostgreSQLClient extends AntaresCore { .map(q => q.trim()) : [sql]; - if (process.env.NODE_ENV === 'development') this._logger(sql);// TODO: replace BLOB content with a placeholder + let connection; + const isPool = this._connection instanceof Pool; + + if (!args.autocommit && args.tabUid) { // autocommit OFF + if (this._connectionsToCommit.has(args.tabUid)) + connection = this._connectionsToCommit.get(args.tabUid); + else { + connection = await this.getConnection(); + await connection.query('START TRANSACTION'); + this._connectionsToCommit.set(args.tabUid, connection); + } + } + else// autocommit ON + connection = isPool ? await this._connection.connect() : this._connection; + + if (args.tabUid && isPool) + this._runningConnections.set(args.tabUid, connection.processID); + + if (args.schema && args.schema !== 'public') + await this.use(args.schema, connection); for (const query of queries) { if (!query) continue; @@ -1395,15 +1529,12 @@ export class PostgreSQLClient extends AntaresCore { let keysArr = []; const { rows, report, fields, keys, duration } = await new Promise((resolve, reject) => { - this._connection.query({ - rowMode: args.nest ? 'array' : null, - text: query - }, async (err, res) => { - timeStop = new Date(); + (async () => { + try { + const res = await connection.query({ rowMode: args.nest ? 'array' : null, text: query }); + + timeStop = new Date(); - if (err) - reject(err); - else { let ast; try { @@ -1492,6 +1623,10 @@ export class PostgreSQLClient extends AntaresCore { }); } catch (err) { + if (isPool && args.autocommit) { + connection.release(); + this._runningConnections.delete(args.tabUid); + } reject(err); } @@ -1500,6 +1635,10 @@ export class PostgreSQLClient extends AntaresCore { keysArr = keysArr ? [...keysArr, ...response] : response; } catch (err) { + if (isPool && args.autocommit) { + connection.release(); + this._runningConnections.delete(args.tabUid); + } reject(err); } } @@ -1514,12 +1653,24 @@ export class PostgreSQLClient extends AntaresCore { keys: keysArr }); } - }); + catch (err) { + if (isPool && args.autocommit) { + connection.release(); + this._runningConnections.delete(args.tabUid); + } + reject(err); + } + })(); }); resultsArr.push({ rows, report, fields, keys, duration }); } + if (isPool && args.autocommit) { + connection.release(); + this._runningConnections.delete(args.tabUid); + } + return resultsArr.length === 1 ? resultsArr[0] : resultsArr; } } diff --git a/src/main/libs/clients/SQLiteClient.js b/src/main/libs/clients/SQLiteClient.js new file mode 100644 index 00000000..1323434e --- /dev/null +++ b/src/main/libs/clients/SQLiteClient.js @@ -0,0 +1,859 @@ +'use strict'; +import sqlite from 'better-sqlite3'; +import { AntaresCore } from '../AntaresCore'; +import dataTypes from 'common/data-types/sqlite'; +import { NUMBER, FLOAT, TIME, DATETIME } from 'common/fieldTypes'; + +export class SQLiteClient extends AntaresCore { + constructor (args) { + super(args); + + this._schema = null; + this._connectionsToCommit = new Map(); + } + + _getTypeInfo (type) { + return dataTypes + .reduce((acc, group) => [...acc, ...group.types], []) + .filter(_type => _type.name === type.toUpperCase())[0]; + } + + /** + * @memberof SQLiteClient + */ + async connect () { + this._connection = this.getConnection(); + } + + getConnection () { + return sqlite(this._params.databasePath, { + fileMustExist: true, + readonly: this._params.readonly + }); + } + + /** + * @memberof SQLiteClient + */ + destroy () {} + + /** + * Executes an USE query + * + * @memberof SQLiteClient + */ + use () {} + + /** + * @param {Array} schemas list + * @returns {Array.} databases scructure + * @memberof SQLiteClient + */ + async getStructure (schemas) { + const { rows: databases } = await this.raw('SELECT * FROM pragma_database_list'); + + const filteredDatabases = databases; + + const tablesArr = []; + const triggersArr = []; + let schemaSize = 0; + + for (const db of filteredDatabases) { + if (!schemas.has(db.name)) continue; + + let { rows: tables } = await this.raw(` + SELECT * + FROM "${db.name}".sqlite_master + WHERE type IN ('table', 'view') + AND name NOT LIKE 'sqlite_%' + ORDER BY name + `); + if (tables.length) { + tables = tables.map(table => { + table.Db = db.name; + return table; + }); + tablesArr.push(...tables); + } + + let { rows: triggers } = await this.raw(`SELECT * FROM "${db.name}".sqlite_master WHERE type='trigger'`); + if (triggers.length) { + triggers = triggers.map(trigger => { + trigger.Db = db.name; + return trigger; + }); + triggersArr.push(...triggers); + } + } + + return filteredDatabases.map(db => { + if (schemas.has(db.name)) { + // TABLES + const remappedTables = tablesArr.filter(table => table.Db === db.name).map(table => { + const tableSize = 0; + schemaSize += tableSize; + + return { + name: table.name, + type: table.type, + rows: false, + size: false + }; + }); + + // TRIGGERS + const remappedTriggers = triggersArr.filter(trigger => trigger.Db === db.name).map(trigger => { + return { + name: trigger.name, + table: trigger.tbl_name + }; + }); + + return { + name: db.name, + size: schemaSize, + tables: remappedTables, + functions: [], + procedures: [], + triggers: remappedTriggers, + schedulers: [] + }; + } + else { + return { + name: db.name, + size: 0, + tables: [], + functions: [], + procedures: [], + triggers: [], + schedulers: [] + }; + } + }); + } + + /** + * @param {Object} params + * @param {String} params.schema + * @param {String} params.table + * @returns {Object} table scructure + * @memberof SQLiteClient + */ + async getTableColumns ({ schema, table }) { + const { rows: fields } = await this.raw(`SELECT * FROM "${schema}".pragma_table_info('${table}')`); + + return fields.map(field => { + const [type, length] = field.type.includes('(') + ? field.type.replace(')', '').split('(').map(el => { + if (!isNaN(el)) el = +el; + return el; + }) + : [field.type, null]; + + return { + name: field.name, + key: null, + type: type.trim(), + schema: schema, + table: table, + numPrecision: [...NUMBER, ...FLOAT].includes(type) ? length : null, + datePrecision: null, + charLength: ![...NUMBER, ...FLOAT].includes(type) ? length : null, + nullable: !field.notnull, + unsigned: null, + zerofill: null, + order: field.cid + 1, + default: field.dflt_value, + charset: null, + collation: null, + autoIncrement: false, + onUpdate: null, + comment: '' + }; + }); + } + + /** + * @param {Object} params + * @param {String} params.schema + * @param {String} params.table + * @returns {Object} table row count + * @memberof SQLiteClient + */ + async getTableApproximateCount ({ schema, table }) { + const { rows } = await this.raw(`SELECT COUNT(*) AS count FROM "${schema}"."${table}"`); + + return rows.length ? rows[0].count : 0; + } + + /** + * @param {Object} params + * @param {String} params.schema + * @param {String} params.table + * @returns {Object} table options + * @memberof SQLiteClient + */ + async getTableOptions ({ schema, table }) { + return { name: table }; + } + + /** + * @param {Object} params + * @param {String} params.schema + * @param {String} params.table + * @returns {Object} table indexes + * @memberof SQLiteClient + */ + async getTableIndexes ({ schema, table }) { + const remappedIndexes = []; + const { rows: primaryKeys } = await this.raw(`SELECT * FROM "${schema}".pragma_table_info('${table}') WHERE pk != 0`); + + for (const key of primaryKeys) { + remappedIndexes.push({ + name: 'PRIMARY', + column: key.name, + indexType: null, + type: 'PRIMARY', + cardinality: null, + comment: '', + indexComment: '' + }); + } + + const { rows: indexes } = await this.raw(`SELECT * FROM "${schema}".pragma_index_list('${table}');`); + + for (const index of indexes) { + const { rows: details } = await this.raw(`SELECT * FROM "${schema}".pragma_index_info('${index.name}');`); + + for (const detail of details) { + remappedIndexes.push({ + name: index.name, + column: detail.name, + indexType: null, + type: index.unique === 1 ? 'UNIQUE' : 'INDEX', + cardinality: null, + comment: '', + indexComment: '' + }); + } + } + + return remappedIndexes; + } + + /** + * @param {Object} params + * @param {String} params.schema + * @param {String} params.table + * @returns {Object} table key usage + * @memberof SQLiteClient + */ + async getKeyUsage ({ schema, table }) { + const { rows } = await this.raw(`SELECT * FROM "${schema}".pragma_foreign_key_list('${table}');`); + + return rows.map(field => { + return { + schema: schema, + table: table, + field: field.from, + position: field.id + 1, + constraintPosition: null, + constraintName: field.id, + refSchema: schema, + refTable: field.table, + refField: field.to, + onUpdate: field.on_update, + onDelete: field.on_delete + }; + }); + } + + async getUsers () {} + + /** + * SHOW CREATE VIEW + * + * @returns {Array.} view informations + * @memberof SQLiteClient + */ + async getViewInformations ({ schema, view }) { + const sql = `SELECT "sql" FROM "${schema}".sqlite_master WHERE "type"='view' AND name='${view}'`; + const results = await this.raw(sql); + + return results.rows.map(row => { + return { + sql: row.sql.match(/(?<=AS ).*?$/gs)[0], + name: view + }; + })[0]; + } + + /** + * DROP VIEW + * + * @returns {Array.} parameters + * @memberof SQLiteClient + */ + async dropView (params) { + const sql = `DROP VIEW "${params.schema}"."${params.view}"`; + return await this.raw(sql); + } + + /** + * ALTER VIEW + * + * @returns {Array.} parameters + * @memberof SQLiteClient + */ + async alterView (params) { + const { view } = params; + try { + await this.dropView({ schema: view.schema, view: view.oldName }); + await this.createView(view); + } + catch (err) { + return Promise.reject(err); + } + } + + /** + * CREATE VIEW + * + * @returns {Array.} parameters + * @memberof SQLiteClient + */ + async createView (params) { + const sql = `CREATE VIEW "${params.schema}"."${params.name}" AS ${params.sql}`; + return await this.raw(sql); + } + + /** + * SHOW CREATE TRIGGER + * + * @returns {Array.} view informations + * @memberof SQLiteClient + */ + async getTriggerInformations ({ schema, trigger }) { + const sql = `SELECT "sql" FROM "${schema}".sqlite_master WHERE "type"='trigger' AND name='${trigger}'`; + const results = await this.raw(sql); + + return results.rows.map(row => { + return { + sql: row.sql.match(/(BEGIN|begin)(.*)(END|end)/gs)[0], + name: trigger, + table: row.sql.match(/(?<=ON `).*?(?=`)/gs)[0], + activation: row.sql.match(/(BEFORE|AFTER)/gs)[0], + event: row.sql.match(/(INSERT|UPDATE|DELETE)/gs)[0] + }; + })[0]; + } + + /** + * DROP TRIGGER + * + * @returns {Array.} parameters + * @memberof SQLiteClient + */ + async dropTrigger (params) { + const sql = `DROP TRIGGER \`${params.schema}\`.\`${params.trigger}\``; + return await this.raw(sql); + } + + /** + * ALTER TRIGGER + * + * @returns {Array.} parameters + * @memberof SQLiteClient + */ + async alterTrigger (params) { + const { trigger } = params; + const tempTrigger = Object.assign({}, trigger); + tempTrigger.name = `Antares_${tempTrigger.name}_tmp`; + + try { + await this.createTrigger(tempTrigger); + await this.dropTrigger({ schema: trigger.schema, trigger: tempTrigger.name }); + await this.dropTrigger({ schema: trigger.schema, trigger: trigger.oldName }); + await this.createTrigger(trigger); + } + catch (err) { + return Promise.reject(err); + } + } + + /** + * CREATE TRIGGER + * + * @returns {Array.} parameters + * @memberof SQLiteClient + */ + async createTrigger (params) { + const sql = `CREATE ${params.definer ? `DEFINER=${params.definer} ` : ''}TRIGGER \`${params.schema}\`.\`${params.name}\` ${params.activation} ${params.event} ON \`${params.table}\` FOR EACH ROW ${params.sql}`; + return await this.raw(sql, { split: false }); + } + + /** + * SHOW COLLATION + * + * @returns {Array.} collations list + * @memberof SQLiteClient + */ + async getCollations () { + return []; + } + + /** + * SHOW VARIABLES + * + * @returns {Array.} variables list + * @memberof SQLiteClient + */ + async getVariables () { + return []; + } + + /** + * SHOW ENGINES + * + * @returns {Array.} engines list + * @memberof SQLiteClient + */ + async getEngines () { + return { + name: 'SQLite', + support: 'YES', + comment: '', + isDefault: true + }; + } + + /** + * SHOW VARIABLES LIKE '%vers%' + * + * @returns {Array.} version parameters + * @memberof SQLiteClient + */ + async getVersion () { + const os = require('os'); + const sql = 'SELECT sqlite_version() AS version'; + const { rows } = await this.raw(sql); + + return { + number: rows[0].version, + name: 'SQLite', + arch: process.arch, + os: `${os.type()} ${os.release()}` + }; + } + + async getProcesses () {} + + async killProcess () {} + + /** + * + * @param {string} tabUid + * @returns {Promise} + */ + async commitTab (tabUid) { + const connection = this._connectionsToCommit.get(tabUid); + if (connection) { + connection.prepare('COMMIT').run(); + return this.destroyConnectionToCommit(tabUid); + } + } + + /** + * + * @param {string} tabUid + * @returns {Promise} + */ + async rollbackTab (tabUid) { + const connection = this._connectionsToCommit.get(tabUid); + if (connection) { + connection.prepare('ROLLBACK').run(); + return this.destroyConnectionToCommit(tabUid); + } + } + + destroyConnectionToCommit (tabUid) { + const connection = this._connectionsToCommit.get(tabUid); + if (connection) { + connection.close(); + this._connectionsToCommit.delete(tabUid); + } + } + + /** + * CREATE TABLE + * + * @returns {Promise} + * @memberof SQLiteClient + */ + async createTable (params) { + const { + schema, + fields, + foreigns, + indexes, + options + } = params; + const newColumns = []; + const newIndexes = []; + const manageIndexes = []; + const newForeigns = []; + + let sql = `CREATE TABLE "${schema}"."${options.name}"`; + + // ADD FIELDS + fields.forEach(field => { + const typeInfo = this._getTypeInfo(field.type); + const length = typeInfo?.length ? field.enumValues || field.numLength || field.charLength || field.datePrecision : false; + + newColumns.push(`"${field.name}" + ${field.type.toUpperCase()}${length && length !== true ? `(${length})` : ''} + ${field.unsigned ? 'UNSIGNED' : ''} + ${field.nullable ? 'NULL' : 'NOT NULL'} + ${field.autoIncrement ? 'AUTO_INCREMENT' : ''} + ${field.default ? `DEFAULT ${field.default}` : ''} + ${field.onUpdate ? `ON UPDATE ${field.onUpdate}` : ''}`); + }); + + // ADD INDEX + indexes.forEach(index => { + const fields = index.fields.map(field => `"${field}"`).join(','); + const type = index.type; + + if (type === 'PRIMARY') + newIndexes.push(`PRIMARY KEY (${fields})`); + else + manageIndexes.push(`CREATE ${type === 'UNIQUE' ? type : ''} INDEX "${index.name}" ON "${options.name}" (${fields})`); + }); + + // ADD FOREIGN KEYS + foreigns.forEach(foreign => { + newForeigns.push(`CONSTRAINT "${foreign.constraintName}" FOREIGN KEY ("${foreign.field}") REFERENCES "${foreign.refTable}" ("${foreign.refField}") ON UPDATE ${foreign.onUpdate} ON DELETE ${foreign.onDelete}`); + }); + + sql = `${sql} (${[...newColumns, ...newIndexes, ...newForeigns].join(', ')})`; + if (manageIndexes.length) sql = `${sql}; ${manageIndexes.join(';')}`; + + return await this.raw(sql); + } + + /** + * ALTER TABLE + * + * @returns {Promise} + * @memberof SQLiteClient + */ + async alterTable (params) { + try { + await this.raw('BEGIN TRANSACTION'); + await this.raw('PRAGMA foreign_keys = 0'); + + const tmpName = `Antares_${params.table}_tmp`; + await this.raw(`CREATE TABLE "${tmpName}" AS SELECT * FROM "${params.table}"`); + await this.dropTable(params); + + const createTableParams = { + schema: params.schema, + fields: params.tableStructure.fields, + foreigns: params.tableStructure.foreigns, + indexes: params.tableStructure.indexes.filter(index => !index.name.includes('sqlite_autoindex')), + options: { name: params.tableStructure.name } + }; + await this.createTable(createTableParams); + const insertFields = createTableParams.fields + .filter(field => { + return ( + params.additions.every(add => add.name !== field.name) && + params.deletions.every(del => del.name !== field.name) + ); + }) + .reduce((acc, curr) => { + acc.push(`"${curr.name}"`); + return acc; + }, []); + + const selectFields = insertFields.map(field => { + const renamedField = params.changes.find(change => `"${change.name}"` === field); + if (renamedField) + return `"${renamedField.orgName}"`; + return field; + }); + + await this.raw(`INSERT INTO "${createTableParams.options.name}" (${insertFields.join(',')}) SELECT ${selectFields.join(',')} FROM "${tmpName}"`); + + await this.dropTable({ schema: params.schema, table: tmpName }); + await this.raw('PRAGMA foreign_keys = 1'); + await this.raw('COMMIT'); + } + catch (err) { + await this.raw('ROLLBACK'); + return Promise.reject(err); + } + } + + /** + * DUPLICATE TABLE + * + * @returns {Promise} + * @memberof SQLiteClient + */ + async duplicateTable (params) { // TODO: retrive table informations and create a copy + const sql = `CREATE TABLE "${params.schema}"."${params.table}_copy" AS SELECT * FROM "${params.schema}"."${params.table}"`; + return await this.raw(sql); + } + + /** + * TRUNCATE TABLE + * + * @returns {Promise} + * @memberof SQLiteClient + */ + async truncateTable (params) { + const sql = `DELETE FROM "${params.schema}"."${params.table}"`; + return await this.raw(sql); + } + + /** + * DROP TABLE + * + * @returns {Promise} + * @memberof SQLiteClient + */ + async dropTable (params) { + const sql = `DROP TABLE "${params.schema}"."${params.table}"`; + return await this.raw(sql); + } + + /** + * @returns {String} SQL string + * @memberof SQLiteClient + */ + getSQL () { + // SELECT + const selectArray = this._query.select.reduce(this._reducer, []); + let selectRaw = ''; + + if (selectArray.length) + selectRaw = selectArray.length ? `SELECT ${selectArray.join(', ')} ` : 'SELECT * '; + + // FROM + let fromRaw = ''; + + if (!this._query.update.length && !Object.keys(this._query.insert).length && !!this._query.from) + fromRaw = 'FROM'; + else if (Object.keys(this._query.insert).length) + fromRaw = 'INTO'; + + fromRaw += this._query.from ? ` ${this._query.schema ? `"${this._query.schema}".` : ''}"${this._query.from}" ` : ''; + + // WHERE + const whereArray = this._query.where + .reduce(this._reducer, []) + ?.map(clausole => clausole.replace('= null', 'IS NULL')); + const whereRaw = whereArray.length ? `WHERE ${whereArray.join(' AND ')} ` : ''; + + // UPDATE + const updateArray = this._query.update.reduce(this._reducer, []); + const updateRaw = updateArray.length ? `SET ${updateArray.join(', ')} ` : ''; + + // INSERT + let insertRaw = ''; + + if (this._query.insert.length) { + const fieldsList = Object.keys(this._query.insert[0]); + const rowsList = this._query.insert.map(el => `(${Object.values(el).join(', ')})`); + + insertRaw = `(${fieldsList.join(', ')}) VALUES ${rowsList.join(', ')} `; + } + + // GROUP BY + const groupByArray = this._query.groupBy.reduce(this._reducer, []); + const groupByRaw = groupByArray.length ? `GROUP BY ${groupByArray.join(', ')} ` : ''; + + // ORDER BY + const orderByArray = this._query.orderBy.reduce(this._reducer, []); + const orderByRaw = orderByArray.length ? `ORDER BY ${orderByArray.join(', ')} ` : ''; + + // LIMIT + const limitRaw = this._query.limit.length ? `LIMIT ${this._query.limit.join(', ')} ` : ''; + + // OFFSET + const offsetRaw = this._query.offset.length ? `OFFSET ${this._query.offset.join(', ')} ` : ''; + + return `${selectRaw}${updateRaw ? 'UPDATE' : ''}${insertRaw ? 'INSERT ' : ''}${this._query.delete ? 'DELETE ' : ''}${fromRaw}${updateRaw}${whereRaw}${groupByRaw}${orderByRaw}${limitRaw}${offsetRaw}${insertRaw}`; + } + + /** + * @param {string} sql raw SQL query + * @param {object} args + * @param {boolean} args.nest + * @param {boolean} args.details + * @param {boolean} args.split + * @returns {Promise} + * @memberof SQLiteClient + */ + async raw (sql, args) { + if (process.env.NODE_ENV === 'development') this._logger(sql);// TODO: replace BLOB content with a placeholder + + args = { + nest: false, + details: false, + split: true, + comments: true, + autocommit: true, + ...args + }; + + if (!args.comments) + sql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '');// Remove comments + + const resultsArr = []; + let paramsArr = []; + const queries = args.split + ? sql.split(/((?:[^;'"]*(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')[^;'"]*)+)|;/gm) + .filter(Boolean) + .map(q => q.trim()) + : [sql]; + + let connection; + + if (!args.autocommit && args.tabUid) { // autocommit OFF + if (this._connectionsToCommit.has(args.tabUid)) + connection = this._connectionsToCommit.get(args.tabUid); + else { + connection = this.getConnection(); + connection.prepare('BEGIN TRANSACTION').run(); + this._connectionsToCommit.set(args.tabUid, connection); + } + } + else// autocommit ON + connection = this._connection; + + for (const query of queries) { + if (!query) continue; + const timeStart = new Date(); + let timeStop; + const keysArr = []; + + const { rows, report, fields, keys, duration } = await new Promise((resolve, reject) => { + (async () => { + let queryResult; + let affectedRows; + let fields; + const detectedTypes = {}; + + try { + const stmt = connection.prepare(query); + + if (stmt.reader) { + queryResult = stmt.all(); + fields = stmt.columns(); + + if (queryResult.length) { + fields.forEach(field => { + detectedTypes[field.name] = typeof queryResult[0][field.name]; + }); + } + } + else { + const info = queryResult = stmt.run(); + affectedRows = info.changes; + } + } + catch (err) { + reject(err); + } + + timeStop = new Date(); + + let remappedFields = fields + ? fields.map(field => { + let [parsedType, length] = field.type?.includes('(') + ? field.type.replace(')', '').split('(').map(el => { + if (!isNaN(el)) + el = +el; + else + el = el.trim(); + return el; + }) + : [field.type, null]; + + if ([...TIME, ...DATETIME].includes(parsedType)) { + const firstNotNull = queryResult.find(res => res[field.name] !== null); + if (firstNotNull && firstNotNull[field.name].includes('.')) + length = firstNotNull[field.name].split('.').pop().length; + } + + return { + name: field.name, + alias: field.name, + orgName: field.column, + schema: field.database, + table: field.table, + tableAlias: field.table, + orgTable: field.table, + type: field.type !== null ? parsedType : detectedTypes[field.name], + length + }; + }).filter(Boolean) + : []; + + if (args.details) { + paramsArr = remappedFields.map(field => { + return { + table: field.table, + schema: field.schema + }; + }).filter((val, i, arr) => arr.findIndex(el => el.schema === val.schema && el.table === val.table) === i); + + for (const paramObj of paramsArr) { + if (!paramObj.table || !paramObj.schema) continue; + + try { + const indexes = await this.getTableIndexes(paramObj); + + remappedFields = remappedFields.map(field => { + // const detailedField = columns.find(f => f.name === field.name); + const fieldIndex = indexes.find(i => i.column === field.name); + if (field.table === paramObj.table && field.schema === paramObj.schema) { + // if (detailedField) { + // const length = detailedField.numPrecision || detailedField.charLength || detailedField.datePrecision || null; + // field = { ...field, ...detailedField, length }; + // } + + if (fieldIndex) { + const key = fieldIndex.type === 'PRIMARY' ? 'pri' : fieldIndex.type === 'UNIQUE' ? 'uni' : 'mul'; + field = { ...field, key }; + }; + } + + return field; + }); + } + catch (err) { + reject(err); + } + } + } + + resolve({ + duration: timeStop - timeStart, + rows: Array.isArray(queryResult) ? queryResult.some(el => Array.isArray(el)) ? [] : queryResult : false, + report: affectedRows !== undefined ? { affectedRows } : null, + fields: remappedFields, + keys: keysArr + }); + })(); + }); + + resultsArr.push({ rows, report, fields, keys, duration }); + } + + return resultsArr.length === 1 ? resultsArr[0] : resultsArr; + } +} diff --git a/src/main/main.js b/src/main/main.js index 570f5b54..87c8ca67 100644 --- a/src/main/main.js +++ b/src/main/main.js @@ -3,6 +3,7 @@ import { app, BrowserWindow, /* session, */ nativeImage, Menu } from 'electron'; import * as path from 'path'; import Store from 'electron-store'; +import * as windowStateKeeper from 'electron-window-state'; import * as remoteMain from '@electron/remote/main'; import ipcHandlers from './ipc-handlers'; @@ -18,15 +19,18 @@ process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = 'true'; // global reference to mainWindow (necessary to prevent window from being garbage collected) let mainWindow; +let mainWindowState; async function createMainWindow () { const icon = require('../renderer/images/logo-32.png'); const window = new BrowserWindow({ - width: 1024, - height: 800, + width: mainWindowState.width, + height: mainWindowState.height, + x: mainWindowState.x, + y: mainWindowState.y, minWidth: 900, minHeight: 550, - title: 'Antares', + title: 'Antares SQL', autoHideMenuBar: true, icon: nativeImage.createFromDataURL(icon.default), webPreferences: { @@ -41,6 +45,9 @@ async function createMainWindow () { backgroundColor: '#1d1d1d' }); + mainWindowState.manage(window); + window.on('moved', saveWindowState); + remoteMain.enable(window.webContents); try { @@ -70,16 +77,10 @@ async function createMainWindow () { } window.on('closed', () => { + window.removeListener('moved', saveWindowState); mainWindow = null; }); - window.webContents.on('devtools-opened', () => { - window.focus(); - setImmediate(() => { - window.focus(); - }); - }); - return window; } @@ -104,17 +105,22 @@ else { // create main BrowserWindow when electron is ready app.on('ready', async () => { + mainWindowState = windowStateKeeper({ + defaultWidth: 1024, + defaultHeight: 800 + }); + mainWindow = await createMainWindow(); createAppMenu(); - if (isDevelopment) - mainWindow.webContents.openDevTools(); + // if (isDevelopment) + // mainWindow.webContents.openDevTools(); - process.on('uncaughtException', (error) => { + process.on('uncaughtException', error => { mainWindow.webContents.send('unhandled-exception', error); }); - process.on('unhandledRejection', (error) => { + process.on('unhandledRejection', error => { mainWindow.webContents.send('unhandled-exception', error); }); }); @@ -160,3 +166,7 @@ function createAppMenu () { Menu.setApplicationMenu(menu); } + +function saveWindowState () { + mainWindowState.saveState(mainWindow); +} diff --git a/src/renderer/components/BaseMap.vue b/src/renderer/components/BaseMap.vue new file mode 100644 index 00000000..c1cbb836 --- /dev/null +++ b/src/renderer/components/BaseMap.vue @@ -0,0 +1,108 @@ + + + + diff --git a/src/renderer/components/FakerSelect.vue b/src/renderer/components/FakerSelect.vue index 53e7a6b9..fc1627b0 100644 --- a/src/renderer/components/FakerSelect.vue +++ b/src/renderer/components/FakerSelect.vue @@ -89,7 +89,7 @@ :type="inputProps().type" :disabled="!isChecked" > -