1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-06-05 21:59:22 +02:00

Compare commits

...

575 Commits

Author SHA1 Message Date
06b0090480 chore(release): 0.7.5 2023-02-26 17:29:31 +01:00
629ce63329 fix: single quotes not properly escaped for random generated content 2023-02-26 17:02:41 +01:00
313e7407eb feat(MySQL): option, disabled by default, to enable table size indicators on sidebar 2023-02-23 08:51:33 +01:00
4458177688 fix(MariaDB): exception with event_scheduler DISABLED with MariaDB 10, fixes #535 2023-02-21 18:07:29 +01:00
ea7865a086 Merge pull request #533 from antares-sql/all-contributors/add-jimcat8
docs: add jimcat8 as a contributor for translation
2023-02-19 10:43:34 +01:00
allcontributors[bot]
ca900f3dcf docs: update .all-contributorsrc [skip ci] 2023-02-19 09:43:23 +00:00
allcontributors[bot]
4f6f28c6e6 docs: update README.md [skip ci] 2023-02-19 09:43:22 +00:00
8caac0f21d Merge pull request #532 from jimcat8/cn_main
Updated zh-CN translation text
2023-02-19 10:43:15 +01:00
tianci li
cacfc1c2eb review 2023-02-19 14:21:42 +08:00
tianci li
2f30c0d42f Updated zh-CN translation text 2023-02-19 14:07:49 +08:00
b1fbc43ab2 fix: unable to import after a failed import, fixes #515 2023-02-13 18:06:55 +01:00
fe9817bf31 chore(release): 0.7.4 2023-02-10 09:26:50 +01:00
ddb7ead083 fix: tables sort in sidebar 2023-02-10 09:26:17 +01:00
9d8c21244b chore(release): 0.7.3 2023-02-09 11:50:16 +01:00
d934ae1e6c fix(SQLite): triggers disappear after editing related table, fixes #523 2023-02-04 13:51:02 +01:00
68f8d48064 chore: minor ts changes 2023-02-04 12:10:09 +01:00
e7e491340a feat(SQLite): added support to INTEGER UNSIGNED 2023-02-04 11:38:30 +01:00
e8447e5655 fix: select of table type stuck when editing an unknown type 2023-02-04 11:34:53 +01:00
6decba316c fix: longtext edit modal opens when it shouldn't, fixes #524 2023-02-04 09:36:29 +01:00
2b5e1e7b39 fix(SQLite): error with integer timestamp fields 2023-02-04 09:07:41 +01:00
a124f04661 Merge pull request #529 from antares-sql/dependabot/npm_and_yarn/mdi/font-7.1.96
build(deps): bump @mdi/font from 7.0.96 to 7.1.96
2023-02-02 16:45:38 +01:00
dependabot[bot]
3ee4ab4d84 build(deps): bump @mdi/font from 7.0.96 to 7.1.96
Bumps [@mdi/font](https://github.com/Templarian/MaterialDesign-Webfont) from 7.0.96 to 7.1.96.
- [Release notes](https://github.com/Templarian/MaterialDesign-Webfont/releases)
- [Commits](https://github.com/Templarian/MaterialDesign-Webfont/compare/v7.0.96...v7.1.96)

---
updated-dependencies:
- dependency-name: "@mdi/font"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 19:05:41 +00:00
174aa3c508 chore(release): 0.7.2 2023-01-22 17:16:04 +01:00
729edd40a6 build: update electron 2023-01-22 15:07:47 +01:00
c7ab3b77a2 fix: allow comments in queies, fixes #519 2023-01-19 14:32:37 +01:00
5624b3b2d7 Merge pull request #520 from dyaskur/master
add copy shortcut and default copy type setting
2023-01-16 18:16:13 +01:00
4c16d8c61f refactor: results table setting section 2023-01-16 18:15:49 +01:00
Dyas🍌 Yaskur🍎
9aca89477f feat: add copy shortcut and default copy type setting 2023-01-16 04:49:44 +07:00
0e80e823d0 fix(SQLite): exception saving tables without INT fields length 2023-01-09 10:02:28 +01:00
ff4bc6c39b feat: connection info icons in footer 2023-01-05 17:21:22 +01:00
b4e1e9ac26 Merge branch 'master' of https://github.com/antares-sql/antares 2023-01-02 09:21:03 +01:00
f177c7f1f1 style: minor refactor 2023-01-02 09:21:01 +01:00
6a67c27915 Merge pull request #406 from antares-sql/dependabot/npm_and_yarn/electron-store-8.1.0
build(deps): bump electron-store from 8.0.2 to 8.1.0
2023-01-02 09:19:15 +01:00
374cedba2b Merge pull request #510 from antares-sql/dependabot/npm_and_yarn/pinia-2.0.28
build(deps): bump pinia from 2.0.27 to 2.0.28
2023-01-02 09:18:55 +01:00
dependabot[bot]
de8097c297 build(deps): bump pinia from 2.0.27 to 2.0.28
Bumps [pinia](https://github.com/vuejs/pinia) from 2.0.27 to 2.0.28.
- [Release notes](https://github.com/vuejs/pinia/releases)
- [Commits](https://github.com/vuejs/pinia/compare/pinia@2.0.27...pinia@2.0.28)

---
updated-dependencies:
- dependency-name: pinia
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-01 19:02:46 +00:00
6fa430adf6 fix: ssh connection closed after idle time, fixes #425 2022-12-29 13:04:20 +01:00
0e7b93c2df chore(release): 0.7.1 2022-12-23 09:25:50 +01:00
843c15e428 fix(MySQL): not every connection gets read-only option 2022-12-23 09:24:05 +01:00
2982b6cb96 ci: change macos build target to macos-11 2022-12-22 22:22:17 +01:00
c08946e932 fix: context submenu outside view when near the edge, fixes #506 2022-12-22 11:27:13 +01:00
55c1604e7f refactor(UI): hide selected connection bar when folder preview 2022-12-21 13:16:56 +01:00
d64fbbad0f Merge pull request #505 from antares-sql/all-contributors/add-dyaskur
docs: add dyaskur as a contributor for code
2022-12-20 21:30:13 +01:00
allcontributors[bot]
c88d734bc0 docs: update .all-contributorsrc [skip ci] 2022-12-20 20:29:48 +00:00
allcontributors[bot]
99d94ea92c docs: update README.md [skip ci] 2022-12-20 20:29:47 +00:00
e4f620c5a1 Merge pull request #500 from dyaskur/add_copy_as_table_rows
feat: Copy rows as html table, so we can paste it to spreadsheet
2022-12-20 21:28:54 +01:00
99f9a9e188 refactor: replace string "Table" with localization 2022-12-20 21:26:33 +01:00
Dyas🍌 Yaskur🍎
2236c8fe75 set copy plain text delimiter to tab 2022-12-19 19:07:31 +07:00
b9a097e2f5 Merge pull request #502 from antares-sql/all-contributors/add-dyaskur
docs: add dyaskur as a contributor for translation
2022-12-19 09:00:17 +01:00
allcontributors[bot]
966446afd6 docs: update .all-contributorsrc [skip ci] 2022-12-19 07:59:59 +00:00
allcontributors[bot]
b681adc632 docs: update README.md [skip ci] 2022-12-19 07:59:58 +00:00
15d0158993 Merge pull request #498 from dyaskur/indonesian-language-translation
Add new language: Bahasa Indonesia
2022-12-19 08:58:25 +01:00
e76d324810 chore: minor change in e2e tests 2022-12-19 08:54:20 +01:00
Dyas🍌 Yaskur🍎
897795ddbb fix: bahasa indonesia typos 2022-12-19 07:34:50 +07:00
Dyas🍌 Yaskur🍎
c32f463ea5 feat: Copy rows as html table, so we can paste it to spreadsheet 2022-12-19 05:33:50 +07:00
Dyas🍌 Yaskur🍎
25e1ba4384 Add new language: Bahasa Indonesia 2022-12-19 04:36:10 +07:00
dependabot[bot]
a71ae05c6f build(deps): bump electron-store from 8.0.2 to 8.1.0
Bumps [electron-store](https://github.com/sindresorhus/electron-store) from 8.0.2 to 8.1.0.
- [Release notes](https://github.com/sindresorhus/electron-store/releases)
- [Commits](https://github.com/sindresorhus/electron-store/compare/v8.0.2...v8.1.0)

---
updated-dependencies:
- dependency-name: electron-store
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-18 15:01:12 +00:00
1bd26ceaa6 feat: option to disable selected query execution, closes #477 2022-12-18 15:59:58 +01:00
56a0361ed2 Merge pull request #493 from antares-sql/all-contributors/add-brdtheo
docs: add brdtheo as a contributor for translation
2022-12-12 09:14:39 +01:00
allcontributors[bot]
c0dd3e0941 docs: update .all-contributorsrc [skip ci] 2022-12-12 08:14:23 +00:00
allcontributors[bot]
33ab5d7491 docs: update README.md [skip ci] 2022-12-12 08:14:22 +00:00
72e6a23fd6 Merge pull request #491 from brdtheo/i18n-fix-french-translation
Fix french translation
2022-12-12 09:11:08 +01:00
brdtheo
fd129a2ad1 fix(i18n): add missing keys for french translation 2022-12-07 22:45:44 +01:00
2c63cbc4e8 chore: update dependencies 2022-12-06 12:56:36 +01:00
c9a33936a0 ci: test target os change 2022-12-03 17:53:16 +01:00
a6bdf69a28 fix: connection default icon not change after client change 2022-12-03 17:53:00 +01:00
dd971d70e0 fix(UI): white background dragging connections inside folder on Linux 2022-12-02 09:38:40 +01:00
669d7e8d4d fix: white background dragging connections or tabs on Linux, fixes #486 2022-12-01 15:38:19 +01:00
02f204a01d Merge pull request #485 from SmileYzn/patch-1
Update pt-BR.ts
2022-11-30 17:50:00 +01:00
Cleverson
023d7aa92d Update pt-BR.ts 2022-11-30 13:45:23 -03:00
4ca40c07d6 ci: ubuntu 20.04 as linux actions target 2022-11-30 15:57:48 +01:00
cf5247bf35 chore(release): 0.7.0 2022-11-30 13:22:26 +01:00
19db29663b refactor(UI): minor change 2022-11-30 13:09:07 +01:00
d010d5aa8f fix(UI): wrong copnnection icons color with light theme 2022-11-30 09:15:15 +01:00
0a1f50a9b9 fix: missing sidebar data after update 2022-11-29 18:18:56 +01:00
e7da5a7040 build(deps): update better-sqlite3 to 8.0.0 2022-11-29 15:19:23 +01:00
2d126d521c refactor: minor improvements 2022-11-29 14:25:30 +01:00
0fca70ebec fix(UI): folder to folder drag glitches 2022-11-29 13:19:41 +01:00
36358584fd Merge pull request #481 from antares-sql/new-sidebar
New connections sidebar
2022-11-28 15:19:24 +01:00
672896414e feat(UI): new settimgbar tooltips 2022-11-28 15:11:29 +01:00
b06bafe06c fix: deletion of connections inside folder 2022-11-28 13:06:01 +01:00
4fe9dfc4d7 feat(UI): footer color based on folder color 2022-11-28 11:56:02 +01:00
7af178a1e4 fix: wrong position moving elements outside folder 2022-11-28 09:42:18 +01:00
212b2bdba9 feat(UI): connections customization 2022-11-27 17:52:32 +01:00
72accb7b0e feat(UI): folders customization 2022-11-26 11:21:47 +01:00
321b387083 refactor(UI): various improvements on sidebar 2022-11-24 16:40:04 +01:00
ece6c6401d feat(UI): folders implementation 2022-11-23 17:52:08 +01:00
5a028a4ea2 refactor: changes to implement folders 2022-11-21 20:19:02 +01:00
83f9b12be0 chore(release): 0.6.0 2022-11-18 14:32:43 +01:00
1c1403f586 fix: incomplete list of collations, fixes #478 2022-11-18 11:30:10 +01:00
038cf68253 Merge pull request #472 from antares-sql/firebirdsql-support
Firebird SQL support
2022-11-17 16:19:59 +01:00
3580faebba chore: update README.md 2022-11-17 16:17:36 +01:00
ae312efbbc feat(Firebird SQL): procedure add/edit/delete support 2022-11-17 15:27:39 +01:00
8e422e3f07 feat(Firebird SQL): trigger add/edit/delete support 2022-11-16 15:16:12 +01:00
7d1967a609 feat(Firebird SQL): view add/edit/delete support 2022-11-16 12:00:12 +01:00
7ff8e2149e fix(Firebird SQL): connection pool issue 2022-11-16 10:12:44 +01:00
1b5cc315dd feat(Firebird SQL): table add/edit/delete support 2022-11-15 16:46:12 +01:00
27566c1dfa feat(Firebird SQL): manual commit mode 2022-11-10 15:52:31 +01:00
03777a2ea3 refactor(Firebird SQL): improve fields metadata detection 2022-11-09 17:41:31 +01:00
d91251d7cb build(deps): update better-sqlite to 7.6.2 2022-11-09 10:48:01 +01:00
0827a04d61 feat(Firebird SQL): support to blob fields 2022-11-08 15:53:21 +01:00
2c8509ff41 feat(Firebird SQL): support to indexes and foreign keys 2022-11-08 14:05:54 +01:00
76df6319c2 feat(Firebird SQL): connections pool 2022-11-07 09:49:36 +01:00
e6f6a022d1 feat: support to text blob fields 2022-11-05 10:22:12 +01:00
95bb41e9db feat(Firebird SQL): display table content and query results 2022-11-04 16:31:10 +01:00
7ab84bde57 initial firebird commit 2022-11-02 14:18:50 +01:00
d190a2dd61 fix: loss of precision updating BIGINT values, fixes #467 2022-10-26 12:26:09 +02:00
d8a298fd20 chore(release): 0.5.19 2022-10-22 14:54:15 +02:00
369622d5af Merge pull request #464 from antares-sql/context-cell-filler
Context menu option to fill table cells
2022-10-20 11:49:43 +02:00
a40d722d7c refactor: remove unnecessary console.log 2022-10-20 11:37:23 +02:00
440f74dfc1 fix: app stuck inserting a random value if field length high 2022-10-20 11:25:23 +02:00
8621ca5333 fix: unable to edit text fields if value is NULL, fixes #466 2022-10-20 10:55:30 +02:00
24edc82b1b feat: uuid fill for string cells 2022-10-19 10:40:56 +02:00
0a2124f2c2 feat: context menu option to fill cell with random values 2022-10-19 01:12:07 +02:00
a8521317a5 Merge branch 'master' of https://github.com/antares-sql/antares into context-cell-filler 2022-10-18 08:50:39 +02:00
88408da745 fix: error joining tables with different schema 2022-10-17 13:55:48 +02:00
d52b7af297 fix(SQLite): save boolean as integer to improve compativility, fixes #463 2022-10-17 12:06:22 +02:00
e4a4696dd3 chore(release): 0.5.18 2022-10-14 15:03:49 +02:00
f0255c0065 Merge pull request #455 from antares-sql/dependabot/npm_and_yarn/sql-formatter-11.0.2
build(deps): bump sql-formatter from 8.2.0 to 11.0.2
2022-10-11 10:36:00 +02:00
9991173685 Merge branch 'master' of https://github.com/antares-sql/antares into dependabot/npm_and_yarn/sql-formatter-11.0.2 2022-10-11 10:29:55 +02:00
dependabot[bot]
874dc6298b build(deps): bump sql-formatter from 8.2.0 to 11.0.2
Bumps [sql-formatter](https://github.com/sql-formatter-org/sql-formatter) from 8.2.0 to 11.0.2.
- [Release notes](https://github.com/sql-formatter-org/sql-formatter/releases)
- [Changelog](https://github.com/sql-formatter-org/sql-formatter/blob/master/.release-it.json)
- [Commits](https://github.com/sql-formatter-org/sql-formatter/compare/v8.2.0...v11.0.2)

---
updated-dependencies:
- dependency-name: sql-formatter
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-10-11 08:12:16 +00:00
5b1b8cf4cc build: update dependencies 2022-10-11 10:11:11 +02:00
a521274d01 feat(PostgreSQL): UUID random generation option on UUID fields, closes #424 2022-10-10 18:08:28 +02:00
86e4c1d58f Merge branch 'master' of https://github.com/antares-sql/antares 2022-10-04 10:12:19 +02:00
ba5a1b68ab fix: trackpad horizontal scroll on tabs not working properly 2022-10-04 10:12:16 +02:00
2c45bce1ee Merge pull request #448 from SmileYzn/master
Update pt-BR.ts
2022-10-01 22:22:34 +02:00
Cleverson
2e05fa4bdc Update pt-BR.ts 2022-09-30 14:43:06 -03:00
dd9c089d27 fix: auto-scroll on sidebar not working, fixes #447 2022-09-29 09:27:29 +02:00
e6955550fa refactor: minor changes in table content context 2022-09-29 09:17:47 +02:00
fe39c1d388 chore(release): 0.5.17 2022-09-22 09:34:28 +02:00
d114f8a651 feat: added more editor font sizes, closes #440 2022-09-21 10:33:44 +02:00
84168d1d75 fix: editor font size doesn't change on new tabs, fixes #442 2022-09-15 19:03:18 +02:00
498a9b48e2 fix: empty definer when editing a view, fixes #437 2022-09-15 18:58:19 +02:00
01f607cd40 fix: "run or reload" shortcut triggers on all connections open 2022-09-08 12:01:57 +02:00
efe134a059 fix: cant run procedures with parameters from leftbar 2022-09-07 18:18:15 +02:00
40cb4dd98d chore: minor changes on macos artifacts action 2022-08-27 09:27:07 +02:00
a142d3c4d7 fix(MacOS): empty options on macos menubar 2022-08-27 09:04:11 +02:00
89da957a49 ci: github action for macos artifacts 2022-08-27 09:02:09 +02:00
05c2f9836c chore(release): 0.5.16 2022-08-26 18:49:51 +02:00
ebc325ae0c fix: issue updating datetime cells with null value, closes #423 2022-08-26 18:48:26 +02:00
39326eb52e fix: unable to set null or delete rows without primary key 2022-08-26 18:31:47 +02:00
df681147aa fix: ts exceptions 2022-08-24 10:23:03 +02:00
ffc645ba5e fix: CTRL+Right/Left not working on text editor, closes #427 2022-08-24 10:04:25 +02:00
1fb1205319 chore: update README.md 2022-08-20 09:18:46 +02:00
c90ab0e880 fix(UI): wrong position of fields resizable area 2022-08-19 16:54:56 +02:00
9dc700e13e fix(UI): editor themes group not visible in select element 2022-08-18 16:10:29 +02:00
6950d0ce5a chore(release): 0.5.15 2022-08-17 16:21:37 +02:00
4df14c3693 feat: dynamic shortcut suggestions on empty query tabs 2022-08-17 16:20:36 +02:00
c05be8304f perf(translation): updated italian translation 2022-08-17 15:29:12 +02:00
31c575dad9 Merge pull request #405 from antares-sql/custom-shortcuts
Shortcuts customization
2022-08-17 11:12:49 +02:00
040657d5ca Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-17 11:05:09 +02:00
5043fafa93 feat: added more events in shortcuts setting 2022-08-17 10:00:23 +02:00
8eb127e458 feat: ability to edit shortcuts 2022-08-16 18:03:38 +02:00
d044a02cb7 feat: ability to add new shortcuts 2022-08-16 13:10:20 +02:00
8cb2c197c8 chore: suppress some stylelint warns 2022-08-15 18:14:51 +02:00
c50d17e82b fix: startup exception 2022-08-15 18:13:53 +02:00
Cleverson
7c186d2dee Update pt-BR.ts 2022-08-12 14:59:22 +02:00
0f219cf9b7 perf: improved keypress detector 2022-08-12 12:40:35 +02:00
75c5a34095 Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-11 11:22:25 +02:00
48877534d1 feat(UI): connection name on left bar, closes #382 #414 2022-08-11 11:14:43 +02:00
c22413fde9 feat: delete shortcuts and restore defaults 2022-08-10 17:59:59 +02:00
77ab8d8a03 build: minor change in ts config 2022-08-09 17:28:33 +02:00
4386c6ab95 chore(release): 0.5.14 2022-08-09 16:21:55 +02:00
19205e0736 style: general lint fix 2022-08-09 16:18:21 +02:00
4fc4ddd1d6 Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-09 16:10:26 +02:00
49b63bc6f2 feat(UI): shortcuts setting UI improved 2022-08-09 16:10:08 +02:00
44eb507a12 fix: unable to open settingbar context menu 2022-08-09 16:04:27 +02:00
1590ffaff0 build: icons for linux builds 2022-08-09 10:48:53 +02:00
3c1bae540f chore(release): 0.5.13 2022-08-09 09:13:11 +02:00
44bb75bc60 feat: list of available shortcuts in settings window 2022-08-08 16:44:40 +02:00
8bb5bb93cf Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-08 11:46:08 +02:00
f64a12a8e9 fix(MySQL): error with ANSI sql_mode 2022-08-07 19:00:12 +02:00
da25823868 Merge branch 'master' of https://github.com/antares-sql/antares into custom-shortcuts 2022-08-05 17:08:48 +02:00
a9fcfd57ec refactor: improved vue-i18n implementation 2022-08-05 17:03:16 +02:00
e2307341f3 Merge pull request #397 from antares-sql/dependabot/npm_and_yarn/vue-i18n-9.2.0
build(deps): bump vue-i18n from 9.1.10 to 9.2.0
2022-08-05 13:17:06 +02:00
09a372e96d refactor: vue-i18n ts improvements 2022-08-05 13:06:08 +02:00
f4da28cca0 refactor: vue-i18n ts improvements 2022-08-05 12:57:56 +02:00
89745b7391 Merge pull request #398 from antares-sql/dependabot/npm_and_yarn/mdi/font-7.0.96
build(deps): bump @mdi/font from 6.9.96 to 7.0.96
2022-08-05 12:26:44 +02:00
104b7c928b fix: set legacy: false 2022-08-05 12:25:14 +02:00
dependabot[bot]
427360d826 build(deps): bump sql-formatter from 4.0.2 to 8.2.0
Bumps [sql-formatter](https://github.com/sql-formatter-org/sql-formatter) from 4.0.2 to 8.2.0.
- [Release notes](https://github.com/sql-formatter-org/sql-formatter/releases)
- [Changelog](https://github.com/sql-formatter-org/sql-formatter/blob/master/.release-it.json)
- [Commits](https://github.com/sql-formatter-org/sql-formatter/compare/v4.0.2...v8.2.0)

---
updated-dependencies:
- dependency-name: sql-formatter
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-05 12:18:53 +02:00
e29d86b409 refactor: shortcuts registration via ShortcutRegister class 2022-08-05 12:07:19 +02:00
Giulio Ganci
0bfa14e1c9 feat: new macos icon 2022-08-03 12:57:17 +02:00
88ba55ec02 build: added deb arm targets 2022-08-03 11:33:26 +02:00
aaff4cf4fe refactor: filter functions as composable 2022-08-03 11:10:16 +02:00
35c54aee84 chore: update README.md 2022-08-02 13:17:13 +02:00
be2e9b21f5 chore: update dependabot.yml 2022-08-02 10:55:19 +02:00
2262278393 Merge branch 'master' of https://github.com/antares-sql/antares 2022-08-02 10:51:43 +02:00
531e17889a chore: update dependabot.yml 2022-08-02 10:51:40 +02:00
a07ed58004 chore: update CONTRIBUTING.md 2022-08-02 10:41:05 +02:00
00dc59a76d ci: remove old ci configs 2022-08-02 10:37:27 +02:00
2f883bfeb2 ci: new ci config 2022-08-02 10:10:20 +02:00
7ff16fccce ci: minor change 2022-08-01 22:32:19 +02:00
dependabot[bot]
3625fbc1b0 build(deps): bump @mdi/font from 6.9.96 to 7.0.96
Bumps [@mdi/font](https://github.com/Templarian/MaterialDesign-Webfont) from 6.9.96 to 7.0.96.
- [Release notes](https://github.com/Templarian/MaterialDesign-Webfont/releases)
- [Commits](https://github.com/Templarian/MaterialDesign-Webfont/compare/v6.9.96...v7.0.96)

---
updated-dependencies:
- dependency-name: "@mdi/font"
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-01 19:10:35 +00:00
dependabot[bot]
deee0d637b build(deps): bump vue-i18n from 9.1.10 to 9.2.0
Bumps [vue-i18n](https://github.com/intlify/vue-i18n-next/tree/HEAD/packages/vue-i18n) from 9.1.10 to 9.2.0.
- [Release notes](https://github.com/intlify/vue-i18n-next/releases)
- [Changelog](https://github.com/intlify/vue-i18n-next/blob/master/CHANGELOG.md)
- [Commits](https://github.com/intlify/vue-i18n-next/commits/v9.2.0/packages/vue-i18n)

---
updated-dependencies:
- dependency-name: vue-i18n
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-08-01 19:09:53 +00:00
8c6950cebd refactor: minor refactors 2022-08-01 18:13:14 +02:00
46167e4473 build: general ci config update 2022-08-01 18:06:57 +02:00
c32a4415d1 Update README.md 2022-07-31 10:43:32 +02:00
1c3d7aa30b feat: copy row as CSV, closes #394 2022-07-29 18:53:39 +02:00
664d18efc1 chore: update README.md 2022-07-26 17:21:43 +02:00
cc941dfc04 chore(release): 0.5.12 2022-07-26 14:59:06 +02:00
1d151e9349 fix: error on schema export 2022-07-26 13:33:57 +02:00
addd9fba28 build(deps): bump ace-builds from 1.4.14 to 1.8.1 2022-07-25 15:25:58 +02:00
a00c19d300 fix: prevent ctrl+a in console 2022-07-25 15:20:15 +02:00
9551afbd2d feat: ability to copy multiple selected rows 2022-07-25 14:56:00 +02:00
1ead76c028 fix: missing defaults on insert row window 2022-07-25 13:09:41 +02:00
d3da15aa13 feat: copy row as SQL INSERT 2022-07-25 12:42:22 +02:00
f3b5de38c4 feat: export table content as SQL INSERT 2022-07-25 12:19:58 +02:00
Askar Kanturin
d4b6d2e9d1 changed readme 2022-07-23 10:20:36 +02:00
Askar Kanturin
e2c106e4e0 fixed typo in readme
i'm no native speaker, but i feel this is a typo
2022-07-23 10:20:36 +02:00
eb60899e6e fix(MySQL): missing quoted identifier for column names in table filter, closes #380 2022-07-22 10:08:33 +02:00
1d367d468d Merge branch 'master' of https://github.com/antares-sql/antares 2022-07-21 11:01:13 +02:00
8ecaedbf6c fix: disable ctrl+alt+(left/right) shortcut on linux 2022-07-21 11:01:10 +02:00
dependabot[bot]
dd1eebd4ec build(deps): bump terser from 5.13.1 to 5.14.2
Bumps [terser](https://github.com/terser/terser) from 5.13.1 to 5.14.2.
- [Release notes](https://github.com/terser/terser/releases)
- [Changelog](https://github.com/terser/terser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/terser/terser/commits)

---
updated-dependencies:
- dependency-name: terser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-21 08:43:24 +02:00
8c83b3f144 fix: missing table on insert new records on session restored tabs 2022-07-20 10:41:44 +02:00
985e5d3527 feat: context menu option to duplicate a table row 2022-07-19 17:48:51 +02:00
78902639eb feat: execute selected query 2022-07-19 15:02:17 +02:00
cb038b374a fix: issue with logger on import/export 2022-07-19 10:10:24 +02:00
eafdb1cc3d chore(release): 0.5.11 2022-07-19 08:14:47 +02:00
91e0630513 fix: unable to edit table fields content on tables with datetime fields 2022-07-19 08:08:51 +02:00
bf768c3800 fix: filter persists switching temporary table tabs 2022-07-18 18:29:12 +02:00
0b1aa3dd29 fix: console events disabled in production 2022-07-18 17:21:34 +02:00
ec75f9546a chore(release): 0.5.10 2022-07-18 14:44:30 +02:00
9bc9adb7cf fix: exception on QueryEditor with null modelValue 2022-07-18 14:43:38 +02:00
b4d14d98db refactor: improved console with light theme 2022-07-18 11:58:22 +02:00
c21bd6075c feat: context menu to copy queries from console 2022-07-18 11:58:22 +02:00
44647f5b55 feat: open/close console on single connection 2022-07-18 11:58:22 +02:00
3f9e6d85ca perf: improved resize of text editor resizing console height 2022-07-18 11:58:22 +02:00
6a6f43a718 feat: initial console implementation 2022-07-18 11:58:22 +02:00
f12a04b052 feat: ipc event channel to send logs to renderer 2022-07-18 11:58:22 +02:00
abf829867e feat: Ctrl+PgUp & Ctrl+PgDn to navigate between tabs 2022-07-14 19:30:34 +02:00
b71f04e5aa feat: field names suggestion for tables in the query 2022-07-14 16:09:04 +02:00
7725fafe85 fix: unable to delete by select all in left bar search, closes #368 2022-07-13 18:50:16 +02:00
ed3d35f131 fix(Linux): ctrl+space shortcut not working 2022-07-13 18:25:42 +02:00
e0946f04f7 fix: unable to update data on tables missing primary or unique key 2022-07-13 09:30:30 +02:00
0891e7be8c refactor: disabled autofocus for scheduler timing modal 2022-07-11 11:35:30 +02:00
f312cf5f85 perf(UI): improved visibility of explore bar tooltips 2022-07-11 09:56:33 +02:00
05e0d310ec Merge pull request #363 from goYou/master
feat: Update zh-CN.ts
2022-07-10 09:13:35 +02:00
goYou
1e0b2b4cae Update zh-CN.ts 2022-07-10 14:49:30 +08:00
5ee728cfe4 Merge pull request #361 from antares-sql/dependabot/npm_and_yarn/moment-2.29.4
build(deps): bump moment from 2.29.3 to 2.29.4
2022-07-09 12:41:20 +02:00
a91fa8ff54 fix: fields content language detection not working properly 2022-07-09 12:39:44 +02:00
dependabot[bot]
2c13433900 build(deps): bump moment from 2.29.3 to 2.29.4
Bumps [moment](https://github.com/moment/moment) from 2.29.3 to 2.29.4.
- [Release notes](https://github.com/moment/moment/releases)
- [Changelog](https://github.com/moment/moment/blob/develop/CHANGELOG.md)
- [Commits](https://github.com/moment/moment/compare/2.29.3...2.29.4)

---
updated-dependencies:
- dependency-name: moment
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-09 10:38:14 +00:00
dcc2a4c51c refactor: replaced @vscode/vscode-languagedetection with custom language detection 2022-07-09 12:37:30 +02:00
7537dff401 chore(release): 0.5.9 2022-07-06 14:42:32 +02:00
853ee1f572 revert: revert to better-sqlite 7.5.1 due build issues 2022-07-06 10:43:32 +02:00
cf9c7c600a fix: error on export schema 2022-07-06 10:26:24 +02:00
73b88cad9e Merge branch 'master' of https://github.com/antares-sql/antares 2022-07-06 09:37:21 +02:00
d2eb31a63d perf(UI): improved focus visibility for buttons 2022-07-06 09:37:18 +02:00
d6b36b1f80 Merge pull request #353 from antares-sql/dependabot/npm_and_yarn/better-sqlite3-7.5.3
build(deps): bump better-sqlite3 from 7.5.1 to 7.5.3
2022-07-05 18:20:56 +02:00
dependabot[bot]
d66b932683 build(deps): bump better-sqlite3 from 7.5.1 to 7.5.3
Bumps [better-sqlite3](https://github.com/WiseLibs/better-sqlite3) from 7.5.1 to 7.5.3.
- [Release notes](https://github.com/WiseLibs/better-sqlite3/releases)
- [Commits](https://github.com/WiseLibs/better-sqlite3/compare/v7.5.1...v7.5.3)

---
updated-dependencies:
- dependency-name: better-sqlite3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-05 06:59:47 +00:00
20f5497034 Merge pull request #341 from antares-sql/dependabot/npm_and_yarn/vue-3.2.37
build(deps): bump vue from 3.2.33 to 3.2.37
2022-07-05 08:54:40 +02:00
d4ed886489 Merge pull request #339 from antares-sql/dependabot/npm_and_yarn/mdi/font-6.9.96
build(deps): bump @mdi/font from 6.1.95 to 6.9.96
2022-07-05 08:54:30 +02:00
dependabot[bot]
aaa14f112a build(deps): bump vue from 3.2.33 to 3.2.37
Bumps [vue](https://github.com/vuejs/core) from 3.2.33 to 3.2.37.
- [Release notes](https://github.com/vuejs/core/releases)
- [Changelog](https://github.com/vuejs/core/blob/main/CHANGELOG.md)
- [Commits](https://github.com/vuejs/core/compare/v3.2.33...v3.2.37)

---
updated-dependencies:
- dependency-name: vue
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-04 15:41:08 +00:00
dependabot[bot]
e0f3ff6939 build(deps): bump @mdi/font from 6.1.95 to 6.9.96
Bumps [@mdi/font](https://github.com/Templarian/MaterialDesign-Webfont) from 6.1.95 to 6.9.96.
- [Release notes](https://github.com/Templarian/MaterialDesign-Webfont/releases)
- [Commits](https://github.com/Templarian/MaterialDesign-Webfont/compare/v6.1.95...v6.9.96)

---
updated-dependencies:
- dependency-name: "@mdi/font"
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-07-04 15:41:01 +00:00
72a328785c Merge pull request #333 from antares-sql/new-connection-management
New connections management
2022-07-04 17:39:56 +02:00
4c2a1998a9 Merge branch 'master' of https://github.com/antares-sql/antares into new-connection-management 2022-07-04 17:25:37 +02:00
8e705706ae feat: ability to pin/unpin and delete connections from the "all connections" modal 2022-07-04 17:03:24 +02:00
56b0a4815c feat: option to disable scratchpad 2022-07-04 15:10:40 +02:00
a9a4344a71 feat: ctrl/cmd+space to open all connections modal 2022-07-04 12:42:33 +02:00
ec5ab73b19 feat: search form in all connections modal 2022-07-04 12:27:04 +02:00
71a5b5c828 fix: missing option for untrusted ssl connection on connections edit panel 2022-07-03 22:07:28 +02:00
4519829aa2 chore(release): 0.5.8 2022-07-02 15:32:02 +02:00
a703dcc53e feat: modal with all connections 2022-07-02 15:30:36 +02:00
36e98e0742 feat: connections sorted by last usage by default and option to pin them 2022-06-30 18:20:14 +02:00
a45d76e8b4 fix: exception on new scheduler tab 2022-06-30 16:42:29 +02:00
7702ca025f fix: error on modals missing focusable elements 2022-06-30 10:05:35 +02:00
f632a0f189 initial implementation of new feature 2022-06-29 19:05:45 +02:00
e97da37103 feat: context shortcut to disconnect from left bar 2022-06-29 13:17:33 +02:00
6573fe69ac fix: connection string field doesn't appear switching to postgre when editing a connection 2022-06-29 11:20:08 +02:00
902c29ffa5 feat(MySQL): option to disable foreign key checks when empty a table 2022-06-29 10:48:21 +02:00
5f57a9f60d fix: ctrl+a on results doesn't work properly 2022-06-28 17:55:18 +02:00
822af44a47 refactor: minor improvements 2022-06-27 18:28:04 +02:00
e42c424a13 fix: focus goes outside modals with tab key navigation 2022-06-26 15:07:37 +02:00
0a3a4827dd fix: result table cells/rows not loses focus clicking outside 2022-06-26 10:21:17 +02:00
a80d227400 fix(Windows): white window buttons with dark theme 2022-06-24 18:17:37 +02:00
cfd82c8f41 fix: editor gutter pin not working 2022-06-24 17:26:28 +02:00
91d0735a5f fix: double context menu on table settings rows 2022-06-23 23:11:43 +02:00
93ce619782 fix(Windows): Windows 7 style window frame at startup 2022-06-23 11:57:25 +02:00
8f01740475 fix(UI): wrong tables scrollable height after switching tabs 2022-06-22 18:47:32 +02:00
869c75f654 Merge pull request #324 from antares-sql/dependabot/npm_and_yarn/electron-19.0.5
build(deps-dev): bump electron from 17.4.3 to 19.0.5
2022-06-21 21:44:06 +02:00
dependabot[bot]
14aff67d2d build(deps-dev): bump electron from 17.4.3 to 19.0.5
Bumps [electron](https://github.com/electron/electron) from 17.4.3 to 19.0.5.
- [Release notes](https://github.com/electron/electron/releases)
- [Changelog](https://github.com/electron/electron/blob/main/docs/breaking-changes.md)
- [Commits](https://github.com/electron/electron/compare/v17.4.3...v19.0.5)

---
updated-dependencies:
- dependency-name: electron
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-06-21 16:11:11 +00:00
174579bf8c Merge pull request #248 from antares-sql/ts-renderer
TypeScript in renderer process
2022-06-21 18:09:42 +02:00
0eab0a7140 Merge branch 'master' of https://github.com/antares-sql/antares into ts-renderer 2022-06-21 18:08:43 +02:00
a103617ce8 refactor: ts and composition api on missing components 2022-06-21 17:54:47 +02:00
61ec3cbd4e Merge branch 'master' of https://github.com/antares-sql/antares 2022-06-20 08:49:29 +02:00
1765d9fd0b chore: dependabot monthly interval 2022-06-20 08:49:26 +02:00
329656ff1d Merge pull request #309 from toriphes/feat/base-select-max-visible-options
feat: add max visible options prop
2022-06-20 08:46:47 +02:00
Giulio Ganci
067a6f3507 feat: add max visible options prop 2022-06-19 16:58:52 +02:00
d12c6f5210 chore(release): 0.5.7 2022-06-19 16:11:12 +02:00
89e8d9fcdb refactor: ts and composition api on WorkspaceTabNew* components 2022-06-14 20:02:17 +02:00
ee623b0a0f fix: unable to add new table fields 2022-06-14 11:48:36 +02:00
33a4663694 Merge branch 'master' of https://github.com/antares-sql/antares into ts-renderer 2022-06-13 09:29:05 +02:00
c37138c6f5 ci: fix linux upload artifacts github action [skip ci] 2022-06-12 19:58:22 +02:00
e754877ee6 Merge branch 'master' of https://github.com/antares-sql/antares 2022-06-12 18:30:48 +02:00
ed38a9e7ff ci: linux upload artifacts github action 2022-06-12 18:30:44 +02:00
6bad032f0d fix(Linux): setting bar tooltip position 2022-06-11 14:26:51 +02:00
d214c1f35b fix: reload tab content on tab sort 2022-06-11 01:11:08 +02:00
77d9cac092 fix: fields sorting in table setting tabs 2022-06-10 23:29:34 +02:00
cba2ce2e37 fix: selected foreign key value not visible in the insert row modal 2022-06-10 20:02:26 +02:00
bd46d17424 refactor: ts and composition api on WorkspaceExplorebar* components 2022-06-09 20:08:32 +02:00
5b33419b64 fix: exception on app start setting window title 2022-06-08 14:55:29 +02:00
00242697a1 feat: dynamic app window title 2022-06-08 13:24:14 +02:00
85cec05f70 perf(Linux): title bar improvements 2022-06-08 13:04:19 +02:00
5fa8bf38e4 perf(Windows): title bar improvements 2022-06-07 18:32:37 +02:00
23acf00def fix: main process not closed after window close on some conditions 2022-06-07 09:33:03 +02:00
be70b5be7f refactor: ts on ipc api 2022-06-05 17:57:44 +02:00
7fc01227e7 refactor: ts and composition api on more components 2022-06-04 18:37:16 +02:00
1c666a07d8 Merge pull request #289 from toriphes/feat/hotkeys
Feat: Hokeys to navigate between tabs and result sets
2022-06-04 15:20:08 +02:00
Giulio Ganci
49abd1ea7f feat: hotkeys to navigate inside a table resultset 2022-06-04 08:45:48 +02:00
Giulio Ganci
d3b9e08446 feat: hotkeys to navigate forward or backward between tabs 2022-06-03 18:56:19 +02:00
20b814378b chore: package.json changes 2022-06-02 12:50:05 +02:00
8ce1d1a964 chore(release): 0.5.6 2022-06-02 11:31:10 +02:00
d151c7254e build: Windows icon improvements 2022-06-02 11:17:53 +02:00
26aad519df perf: improved precision of MariaDB or MySQL auto detection 2022-06-02 09:50:16 +02:00
31b7999bba fix: empty query tab schema select if no schema selected 2022-06-02 09:46:49 +02:00
caf776bd55 fix: inline field update not working with tables missing primary key 2022-06-01 18:31:25 +02:00
a7d5e1973c fix(SQLite): unable to insert rows with TEXT fields 2022-06-01 09:56:45 +02:00
8870304c15 fix(UI): select closes clicking on scrollbar 2022-05-29 16:42:41 +02:00
2007305ff0 refactor: ts on pinia store 2022-05-28 18:43:56 +02:00
e97401e27d Merge branch 'master' of https://github.com/antares-sql/antares into ts-renderer 2022-05-25 14:41:15 +02:00
62f6fd16d5 refactor: ts on i18n 2022-05-24 23:02:40 +02:00
cdca6eaa35 refactor: ts and composition api for modals 2022-05-24 23:02:14 +02:00
34e8d3e5b1 chore(release): 0.5.5 2022-05-24 14:25:04 +02:00
6c8a36e947 refactor(UI): double click to edit field type or collation 2022-05-23 16:35:50 +02:00
99b1c1be12 Merge pull request #245 from toriphes/feat/advanced-dropdown-list
feat/advanced-dropdown-list
2022-05-23 16:31:19 +02:00
3991382153 Merge branch 'feat/advanced-dropdown-list' of https://github.com/toriphes/antares into pr/toriphes/245 2022-05-23 16:19:35 +02:00
allcontributors[bot]
3b57b7ef3b docs: update .all-contributorsrc [skip ci] 2022-05-23 16:13:51 +02:00
allcontributors[bot]
45d599ad7f docs: update README.md [skip ci] 2022-05-23 16:13:51 +02:00
9082960310 feat(translation): russian translation, closes #266 2022-05-23 16:11:54 +02:00
Giulio Ganci
5398964190 feat: added dropdown animation 2022-05-22 15:45:16 +02:00
5d5f1da97b perf(UI): max height for query text area increased 2022-05-19 09:30:43 +02:00
84826ff4c0 refactor: ts and composition api on more elements 2022-05-17 19:11:31 +02:00
c95c593c74 chore: create CODE_OF_CONDUCT.md 2022-05-15 19:08:06 +02:00
5a50ba88e8 Merge branch 'master' of https://github.com/antares-sql/antares into ts-renderer 2022-05-15 18:23:09 +02:00
c5baf2b0d3 fix: query tab content disappears reordering or closing other tabs, closes #261 2022-05-15 18:15:05 +02:00
a082514f88 fix(PostgreSQL): idle timeout disabled 2022-05-15 17:37:54 +02:00
c826888b0d fix: SSH tunnel connection error with private key, closes #260 2022-05-14 11:24:24 +02:00
8a55b36527 refactor: ts and composition api for single instance components 2022-05-14 11:15:42 +02:00
b0d464952f Merge branch 'master' of https://github.com/antares-sql/antares into pr/toriphes/245 2022-05-14 09:57:09 +02:00
Giulio Ganci
7c45203636 fix(UI): BaseSelect keyboard navigation 2022-05-13 18:35:02 +02:00
Giulio Ganci
71b0736d0d fix(UI): BaseSelect style 2022-05-13 18:20:47 +02:00
Giulio Ganci
42bc9196ff feat(UI): select tab replace with BaseSelect component 2022-05-11 23:30:31 +02:00
Giulio Ganci
f7e04d6333 feat(UI): BaseSelect supports disabled options 2022-05-11 22:57:13 +02:00
45b2eb2934 fix: reactivity problem on BaseVirtualScroll component 2022-05-11 11:27:29 +02:00
9ee1b3023d build: electron-updater downgrade [skip ci] 2022-05-10 19:16:06 +02:00
79d9acb471 chore(release): 0.5.4 2022-05-10 18:13:30 +02:00
e02565c0d9 perf(UI): left alignment for numbers in result tables, closes #249 2022-05-10 15:19:47 +02:00
ff272440bd fix: unable to insert auto-generated datetime fields 2022-05-10 15:14:34 +02:00
e62f280528 fix: app blocked by BIT fields with no default, closes #256 2022-05-10 15:13:08 +02:00
6d6151814e fix: SSH tunnel not working 2022-05-10 14:44:45 +02:00
58611bf07f fix: file upload input not working 2022-05-10 14:43:08 +02:00
d494b17df7 fix: 2022-05-10 13:22:26 +02:00
ae377a6c3c refactor: ts and composition api for base components 2022-05-10 13:02:01 +02:00
cc5910b88f refactor: common to ts 2022-05-10 12:57:25 +02:00
Giulio Ganci
2b436d8613 feat(UI): BaseSelect disabled state 2022-05-10 10:29:38 +02:00
Giulio Ganci
1869e6a148 feat(UI): BaseSelect supports option groups 2022-05-09 17:31:58 +02:00
d1bfa282c3 build: ts config for renderer 2022-05-09 11:48:30 +02:00
Giulio Ganci
302c66457d feat(UI): ForeignKeySelect implements BaseSelect component 2022-05-09 11:29:25 +02:00
Giulio Ganci
0043d07708 feat(UI): BaseSelect option list scrolls automatically using up/down keys 2022-05-08 18:59:00 +02:00
Ngô Quốc Đạt
e0f85f469f Added missing translations for vi-VN 2022-05-08 16:29:48 +02:00
Giulio Ganci
a037d0cc01 feat(UI): BaseSelect in table filters 2022-05-08 13:15:39 +02:00
Giulio Ganci
5582a12bbf feat(UI): BaseSelect small variant 2022-05-08 13:14:40 +02:00
Giulio Ganci
22622df2cf feat(UI): initial BaseSelect integration 2022-05-08 09:45:37 +02:00
Giulio Ganci
745d551cc9 feat(UI): new BaseSelect component 2022-05-08 09:44:52 +02:00
a93e71d751 chore(release): 0.5.3 2022-05-08 09:25:59 +02:00
2a7433da16 refactor: removed pinia ipc plugins 2022-05-08 00:12:23 +02:00
fd5dca2450 ci: e2e tests on separate github action 2022-05-07 23:20:31 +02:00
da6481f458 build: fix compilation issues 2022-05-07 22:50:11 +02:00
c7417809f4 refactor: minor improvement in changelog parsing 2022-05-07 16:13:22 +02:00
5cb8ec65ad refactor: ts improvements 2022-05-07 09:46:07 +02:00
e4c5d9b404 fix(MySQL): creating temporary tables on export to overcome view dependency errors 2022-05-06 17:20:06 +02:00
bfdb463390 fix: unable to set an empty string as field default 2022-05-05 23:09:10 +02:00
9fcc7d1cef fix(MySQL): support to ANSI_QUOTES mode not working, closes #243 2022-05-05 17:18:18 +02:00
70cb92521f refactor: Invitation to contribute in translations on settings 2022-05-04 11:24:48 +02:00
981d31957f Merge pull request #232 from antares-sql/dependabot/npm_and_yarn/electron-updater-5.0.1
build(deps): bump electron-updater from 4.6.5 to 5.0.1
2022-05-03 18:12:04 +02:00
619478c072 Merge pull request #230 from antares-sql/dependabot/npm_and_yarn/electron-builder-23.0.3
build(deps-dev): bump electron-builder from 22.14.13 to 23.0.3
2022-05-03 17:01:40 +02:00
eb1afed108 fix: LIKE operator in table filter not properly working, closes #242 2022-05-03 14:34:27 +02:00
0fa22fbe72 feat: default open schema if only one present 2022-05-01 10:46:32 +02:00
5e4abd3e81 fix: prevents query tabs targets previous schema if not in explorebar, closes #236 2022-05-01 10:23:03 +02:00
dependabot[bot]
81d897c7b3 build(deps): bump electron-updater from 4.6.5 to 5.0.1
Bumps [electron-updater](https://github.com/electron-userland/electron-builder/tree/HEAD/packages/electron-updater) from 4.6.5 to 5.0.1.
- [Release notes](https://github.com/electron-userland/electron-builder/releases)
- [Changelog](https://github.com/electron-userland/electron-builder/blob/master/packages/electron-updater/CHANGELOG.md)
- [Commits](https://github.com/electron-userland/electron-builder/commits/electron-updater@5.0.1/packages/electron-updater)

---
updated-dependencies:
- dependency-name: electron-updater
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-30 15:34:36 +00:00
dependabot[bot]
b148c210a6 build(deps-dev): bump electron-builder from 22.14.13 to 23.0.3
Bumps [electron-builder](https://github.com/electron-userland/electron-builder/tree/HEAD/packages/electron-builder) from 22.14.13 to 23.0.3.
- [Release notes](https://github.com/electron-userland/electron-builder/releases)
- [Changelog](https://github.com/electron-userland/electron-builder/blob/master/packages/electron-builder/CHANGELOG.md)
- [Commits](https://github.com/electron-userland/electron-builder/commits/v23.0.3/packages/electron-builder)

---
updated-dependencies:
- dependency-name: electron-builder
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-30 15:34:19 +00:00
75aa299f8d Merge pull request #238 from antares-sql/vue3-migration
Vue3 migration
2022-04-30 17:31:02 +02:00
f4795eb92a chore: update CONTRIBUTING.md 2022-04-30 17:26:08 +02:00
18b66b5032 fix: missing tabs uid 2022-04-30 17:15:33 +02:00
cdbadbb11a remove @vue/compat 2022-04-30 16:11:44 +02:00
47e1f27bb8 fix: unable to disconnect from database 2022-04-30 12:15:00 +02:00
4be0f6bbbc Merge branch 'master' of https://github.com/Fabio286/antares into vue3-migration 2022-04-30 12:03:32 +02:00
ff8bb45d6d fix: missing storeToRefs imports 2022-04-30 11:45:49 +02:00
0d52282aa8 refactor: migration to pinia 2022-04-30 00:47:37 +02:00
e9dedfaf32 fix: query editor table fields suggestion 2022-04-28 13:22:15 +02:00
9f0ec5e0ce vue devtools integrated in chromium devtools 2022-04-28 10:34:44 +02:00
Giulio Ganci
1174bab0cc fix: verbose devtool loggin with missing sourcemap 2022-04-27 22:11:30 +02:00
9dd685b062 refactor: initial pinia implementation 2022-04-27 18:23:48 +02:00
0821586bb3 standalone vue-devtools 2022-04-27 18:23:05 +02:00
350d53642e fix: unable to add parameters to new routines/functions 2022-04-26 13:01:21 +02:00
Giulio Ganci
88eb9f7ab8 fix: can not use vue teleport with props as root element 2022-04-25 22:51:24 +02:00
Giulio Ganci
b0195260c3 fix foreign key dropdown with wrong value 2022-04-25 22:27:26 +02:00
Giulio Ganci
dfe3728269 no more this.$set needed in vue3 2022-04-25 22:11:53 +02:00
daef6f91b0 test: improved e2e tests 2022-04-25 18:26:11 +02:00
d61acf8a00 refactor(SQLite): improved sqlite window title 2022-04-25 17:37:12 +02:00
8b04a2b7dd refactor: teleport for modals 2022-04-25 13:45:07 +02:00
6780401cb7 refactor: vue3 transitions 2022-04-24 23:24:21 +02:00
b8e734d827 refactor: v-model on custom components 2022-04-24 23:10:25 +02:00
4f8bc26349 refactor: improved Proxy handlement on ipc 2022-04-24 12:17:29 +02:00
Giulio Ganci
3eb781021c enabling vue compat 2022-04-23 16:15:54 +02:00
Giulio Ganci
3cca3ed2b3 fix: undefined uid variable in the setting bar 2022-04-23 09:03:28 +02:00
434b9f8284 refactor: toRaw to handle Proxy objects on ipc 2022-04-22 23:33:12 +02:00
690cdcb2eb fix(SQLite): tables with sqlite in name not visible, closes #239 2022-04-22 23:01:30 +02:00
c50cbc577f fix: various warnings and exceptions 2022-04-22 17:49:13 +02:00
6af0c33461 fix: locale change 2022-04-22 17:45:12 +02:00
e60789f320 refactor: unproxify ipc params 2022-04-22 12:17:27 +02:00
afa23f3ef1 refactor: emits in components 2022-04-22 12:16:02 +02:00
7c4b605467 Merge branch 'master' of https://github.com/Fabio286/antares into vue3-migration 2022-04-21 14:42:33 +02:00
443170bbb1 refactor: vue3 migration in progress 2022-04-21 14:39:24 +02:00
3450497010 Merge pull request #237 from SmileYzn/patch-1
Fixed a typo
2022-04-21 13:29:39 +02:00
Cleverson
eaf38df1b7 Fixed a typo
Fixed a typo
2022-04-20 16:14:14 -03:00
a9f88e5784 chore: update bug_report.md [skip ci] 2022-04-19 11:47:50 +02:00
472fa6f430 fix: wrong path module importation 2022-04-17 13:00:53 +02:00
f82db96f34 fix: importer webpack config 2022-04-17 13:00:53 +02:00
79f32ca442 refactor: db import ts refactor 2022-04-17 13:00:53 +02:00
ce0f278caf refactor: db exporter ts refactor 2022-04-17 13:00:53 +02:00
6adc93e1cd refactor: ipc handlers ts refactor 2022-04-17 13:00:53 +02:00
5e2ad8c377 refactor: sqlite client ts refactor 2022-04-17 13:00:53 +02:00
d85662cb7d refactor: posgtre client ts refactor 2022-04-17 13:00:53 +02:00
e3907914f2 build: fixed module resolution and workers webpack config 2022-04-17 13:00:53 +02:00
c6c14fbf2b refactor: mysql client ts refactor 2022-04-17 13:00:53 +02:00
3975359292 build: typescript config 2022-04-17 13:00:53 +02:00
9a0f982723 fix: wrong path module importation 2022-04-17 12:27:46 +02:00
b4d9821300 fix: importer webpack config 2022-04-17 12:11:00 +02:00
75a41769bf refactor: db import ts refactor 2022-04-17 12:01:07 +02:00
5dbc127b51 refactor: db exporter ts refactor 2022-04-15 23:13:23 +02:00
a315eeae6c refactor: ipc handlers ts refactor 2022-04-15 14:56:13 +02:00
25a6fded2e refactor: sqlite client ts refactor 2022-04-14 18:25:13 +02:00
42fcded9f1 refactor: posgtre client ts refactor 2022-04-14 09:15:16 +02:00
186cb85d2e build: fixed module resolution and workers webpack config 2022-04-12 17:59:22 +02:00
fc1d6fba7f refactor: mysql client ts refactor 2022-04-12 17:08:05 +02:00
cbef7489b2 build: typescript config 2022-04-12 17:04:11 +02:00
96d6913a7a Merge pull request #229 from SmileYzn/patch-1
Update pt-BR.js
2022-04-11 15:18:26 +02:00
Cleverson
744c623914 Update pt-BR.js 2022-04-11 09:22:24 -03:00
0b861d962d chore(release): 0.5.2 2022-04-10 10:55:23 +02:00
6cc098c6f0 feat(core): option to allow untrusted SSL connections 2022-04-10 10:49:27 +02:00
40828cb3ff Merge pull request #208 from antares-sql/feat/postgre-import-export
feat(PostgreSQL): import/export
2022-04-07 17:56:37 +02:00
6086ca4a80 feat(PostgreSQL): sql dump importer 2022-04-07 12:49:34 +02:00
d92facf518 chore: update README.md 2022-04-05 14:06:36 +02:00
allcontributors[bot]
e9643a0d6b docs: update .all-contributorsrc [skip ci] 2022-04-04 10:32:23 +02:00
allcontributors[bot]
cc609a7051 docs: update README.md [skip ci] 2022-04-04 10:32:23 +02:00
796f61bf2f feat: french translation updated, closes #222 2022-04-04 10:29:11 +02:00
0f9c991f53 fix(PostgreSQL): wrong values exporting table content 2022-04-02 11:44:55 +02:00
638a88a1fb perf(PostgreSQL): improved views exportation 2022-04-01 18:36:02 +02:00
026d74c8c8 fix: ssh tunnel not properly working, closes #220 2022-04-01 09:51:03 +02:00
77f8cac6cf refactor: update repo links 2022-03-31 16:04:47 +02:00
d6fadf5db0 chore: update README.md 2022-03-29 15:47:50 +02:00
408ddeda56 perf(PostgreSQL): improved dump file 2022-03-27 11:41:35 +02:00
88cd097ec0 chore(release): 0.5.1 2022-03-25 09:26:04 +01:00
f12e6a96dd fix(UI): connection buttons out of screen on small displays, closes #213 2022-03-24 17:34:24 +01:00
a8ca8f2f76 feat(PostgreSQL): export functions and procedures 2022-03-23 13:26:46 +01:00
allcontributors[bot]
6fcae957e1 docs: update .all-contributorsrc [skip ci] 2022-03-22 21:38:32 +01:00
allcontributors[bot]
1cd2d8abf3 docs: update README.md [skip ci] 2022-03-22 21:38:32 +01:00
ed3c5fe559 Merge pull request #210 from SmileYzn/patch-1
Added some missing translations for pt-BR
2022-03-22 21:36:52 +01:00
Cleverson
9601c59392 Update pt-BR.js 2022-03-22 14:38:24 -03:00
Cleverson
14d20a30c1 Added some missing translations for pt-BR
Added some translations for pt-BR
2022-03-22 14:29:33 -03:00
42376b4bc6 feat(PostgreSQL): export triggers 2022-03-22 17:25:34 +01:00
e9079adb25 feat(UI): option to disable blur effects, closes #209 2022-03-22 16:13:44 +01:00
86f011f34f feat(PostgreSQL): export views 2022-03-22 12:59:13 +01:00
bb02479b71 feat(PostgreSQL): export user-defined types before tables 2022-03-22 12:40:14 +01:00
a67071e284 feat(PostgreSQL): export tables 2022-03-21 18:32:45 +01:00
8f3efabb69 feat: export database as zip sql file 2022-03-18 18:12:13 +01:00
db628f7722 fix: numeric scale displayed on non decimal fields 2022-03-17 18:17:59 +01:00
e4bd747381 chore: update bug_report.md 2022-03-15 18:39:46 +01:00
88eb113e53 chore: update README.md 2022-03-12 17:42:34 +01:00
9109b2c328 chore(release): 0.5.0 2022-03-12 14:25:04 +01:00
dd070d008d Merge pull request #129 from toriphes/feat/db-import-export
feat(MySQL): db import export
2022-03-12 14:17:48 +01:00
ee415da127 fix(MySQL): exception exporting empty procedures/functions 2022-03-12 10:37:40 +01:00
f0d368e3e3 refactor: minor refactor 2022-03-12 10:01:22 +01:00
4be55f3fe9 feat(MySQL): support to multi spatial fields export 2022-03-12 09:52:40 +01:00
fd00ea42ee refactor: hide export option for PostgreSQL 2022-03-10 10:54:44 +01:00
50b4411e9a Merge pull request #204 from raliqala/fix-and-minimize-con-string
perf(PostgreSQL): Postgres connection string update, better error handling and any connection string accommodation
2022-03-10 10:52:10 +01:00
Topollo
cd0a5dc034 Merge branch 'fix-and-minimize-con-string' of https://github.com/raliqala/antares into fix-and-minimize-con-string 2022-03-10 11:45:54 +02:00
Topollo
9fd427c4ff removed electron-rebuild 2022-03-10 11:44:52 +02:00
f3759b6541 perf(MySQL): prevent memory leak on large dump import 2022-03-10 10:23:22 +01:00
191a354020 chore: delete UsersraliqAppDataLocalnpm-cache_logs2022-03-05T07_59_37_036Z-debug.log 2022-03-10 09:02:16 +01:00
Topollo
7dc314eecf Merge branch 'master' into fix-and-minimize-con-string 2022-03-09 22:14:28 +02:00
Topollo
330a80fe70 perf(PostgreSQL): Postgres connection update, better error handling and connection string accommodation.
Used the pg package parser function to handle connection strings to lowering chances of errors. All other connection string will work here an example for ssl  ```const args = "postgres://user:password@localhost:5432/db?&sslrootcert=./myCaCertificate.pem&sslcert=./myClientCertificate.pem&sslkey=./myPrivateClientKey.pem&ciphers=mytestcipher&ssl=true"``` for ssh these can be used ```ssh: false, sshHost: '', sshUser: '', sshPass: '', sshKey: '', sshPort: 22,```

no breaking changes
2022-03-09 21:52:13 +02:00
Topollo
b2ce533b82 Merge branch 'postgres_con_string' into fix-and-minimize-con-string 2022-03-09 19:41:31 +02:00
Topollo
12ce6b1135 Update testStringDecode.js 2022-03-09 19:40:04 +02:00
Topollo
71c5829702 hi 2022-03-09 19:31:41 +02:00
1c4d5b05b3 feat(UI): toggle tables checkbox by column on export modal 2022-03-07 23:07:42 +01:00
e85197a2cc chore: UsersraliqAppDataLocalnpm-cache_logs2022-03-05T07_59_37_036Z-debug.log 2022-03-07 20:10:44 +01:00
Giulio Ganci
abf2b92e6e feat(UI): auto-refresh schema at the end of the import process 2022-03-06 19:54:32 +01:00
Giulio Ganci
3be826df4b feat(MySQL): enhance export characters escaping 2022-03-06 19:37:12 +01:00
9db6bfd255 refactor: show contributors in settings 2022-03-06 16:02:24 +01:00
allcontributors[bot]
110adf90de docs: update .all-contributorsrc [skip ci] 2022-03-06 09:48:30 +01:00
allcontributors[bot]
40e4fbda15 docs: update README.md [skip ci] 2022-03-06 09:48:30 +01:00
8e983ad2cb refactor(PostgreSQL): minor refactor on UI and code for pg connection string 2022-03-06 09:45:55 +01:00
Topollo
6305752ad1 feat(PostgreSQL): Postgress connection string feature for local and server connection string
This feature is based on this [issue](https://github.com/Fabio286/antares/issues/193)  I tested with the following posgress connection strings postgresql://postgres:pgpassword@127.0.0.1:5432/my_local_databse?connection=local postgres://serveruser:serverpass@test.db.elephantsql.com/my_remote_databse?connection=server  postgres://serveruser:serverpass@test.db.elephantsql.com:5432/my_remote_databse postgresql://postgres:pgpassword@127.0.0.1:5432/my_local_databse.

The connection string decoder is loaded before "test-connection", "check-connection", and "connect"
2022-03-06 09:45:55 +01:00
cc02e2c5a8 refactor(PostgreSQL): minor refactor on UI and code for pg connection string 2022-03-06 09:40:11 +01:00
Topollo
f4a63eae2a feat(PostgreSQL): Postgress connection string feature for local and server connection string
This feature is based on this [issue](https://github.com/Fabio286/antares/issues/193)  I tested with the following posgress connection strings postgresql://postgres:pgpassword@127.0.0.1:5432/my_local_databse?connection=local postgres://serveruser:serverpass@test.db.elephantsql.com/my_remote_databse?connection=server  postgres://serveruser:serverpass@test.db.elephantsql.com:5432/my_remote_databse postgresql://postgres:pgpassword@127.0.0.1:5432/my_local_databse.

The connection string decoder is loaded before "test-connection", "check-connection", and "connect"
2022-03-06 02:20:10 +02:00
763be8532d fix: wrong soft sort algorithm for numeric fields, closes #199 2022-03-05 21:58:56 +01:00
Giulio Ganci
a6f5645a22 feat(UI): better real-time import stats 2022-03-05 18:55:11 +01:00
Giulio Ganci
bbe13f27dc perf(MySQL): import tasks managed with async queue 2022-03-05 18:54:08 +01:00
f444746f46 perf(MySQL): import performance improvement 2022-03-05 17:00:05 +01:00
b4af645941 fix(MySQL):spatial fielts support on export 2022-03-03 22:52:50 +01:00
a5c8daa5b8 chore: workers debug config 2022-03-01 22:15:33 +01:00
1a9fc37285 fix(MySQL): missing initial delimiter for exported procedures 2022-03-01 19:05:53 +01:00
f0351e5b94 fix(MySQL): missing functions and procedures definer escapes on exporter 2022-03-01 10:15:06 +01:00
9bda4e71b7 Merge branch 'feat/db-import-export' of https://github.com/toriphes/antares into pr/toriphes/129 2022-02-28 23:33:16 +01:00
7c00055034 Merge branch 'master' of https://github.com/Fabio286/antares into pr/toriphes/129 2022-02-28 22:00:13 +01:00
4479a9600b fix: wrong schema and table size on explore bar 2022-02-28 14:19:07 +01:00
Giulio Ganci
7a6bd8bdbd fix: sql parser hangs during import 2022-02-27 17:33:03 +01:00
ad713fcf35 chore(release): 0.4.4 2022-02-27 14:07:24 +01:00
251795e2d2 Merge branch 'master' into feat/db-import-export 2022-02-26 10:19:15 +01:00
45cda7a7cc Merge branch 'master' of https://github.com/Fabio286/antares into pr/toriphes/129 2022-02-26 10:14:00 +01:00
b7039553cc fix: bigint support, closes #197 2022-02-26 10:02:23 +01:00
ddee68b4c2 ci: set windows-2019 for GitHub Actions 2022-02-26 10:01:46 +01:00
573ac6d42e perf: use fork() for the import process 2022-02-24 13:14:57 +01:00
265f28b4d9 fix: zero-padded bit fields beyond length 2022-02-21 21:40:26 +01:00
1990d9a3d4 perf(MySQL): improved several field types support on exporter 2022-02-19 12:40:54 +01:00
748d44977e perf: use fork() for the export process 2022-02-18 18:16:13 +01:00
4051eff382 build: webpack workers configuration 2022-02-17 18:47:50 +01:00
4276586e11 fix(MySQL): procedures exportation 2022-02-16 12:58:24 +01:00
832fb0fb03 Merge branch 'feat/db-import-export' of https://github.com/toriphes/antares into pr/toriphes/129 2022-02-16 09:16:14 +01:00
328ab61757 Merge branch 'master' of https://github.com/Fabio286/antares into pr/toriphes/129 2022-02-16 09:14:46 +01:00
95d15de1bd chore: update README.md 2022-02-16 08:57:54 +01:00
7dcd4441c4 feat(SQLite): manual commit mode 2022-02-15 09:23:07 +01:00
d81e0911ab feat(PostgreSQL): manual commit mode 2022-02-15 09:23:07 +01:00
5bfff649e9 feat: reminder for uncommitted changes closing a tab 2022-02-15 09:23:07 +01:00
76743e8f7c feat: execution notification for ROLLBACK and COMMIT 2022-02-15 09:23:07 +01:00
4ed2f9a939 feat(MySQL): manual commit mode 2022-02-15 09:23:07 +01:00
c5eb73ed3f chore: update electron 2022-02-15 09:21:14 +01:00
fa3f3e1fd8 fix(MySQL): default value not displayed for DECIMAL fields 2022-02-05 09:43:37 +01:00
2c7c97852f chore(release): 0.4.3 2022-01-30 12:39:54 +01:00
48ebf23bd1 feat(MySQL): spatial fields support (#165)
* feat: POINT field support

* feat(MySQL): support to LINESTRING, POLYGON and GEOMETRY fields

* refactor: removed links from map attribution

* feat(MySQL): support to MULTIPOINT, MULTILINESTRING, MULTIPOLYGON and GEOMCOLLECTION fields

* test: temporary fix on Windows tests
2022-01-30 11:45:24 +01:00
64deedc5ad test: temporary skip tests on WIndows 2022-01-30 11:44:01 +01:00
9f033fb994 fix: indexes and foreign keys not cleared after deletion of related field, closes #182 2022-01-28 23:57:53 +01:00
401cb49687 refactor: improved temporary fix to Windows 7 style frame 2022-01-28 09:19:49 +01:00
1356011ba3 fix(Windows): temporary fix to Windows 7 style frame on app startup, closes #169 2022-01-27 23:40:03 +01:00
0cfd7938ee fix: scale on numeric fields that doesn't support it 2022-01-27 09:12:01 +01:00
745b55a942 chore: update dependencies 2022-01-25 09:08:45 +01:00
eef7c1dcec perf: support of scale in field's length setting 2022-01-22 12:29:49 +01:00
aa8fc545d7 Rename zh_CN.js to zh-CN.js 2022-01-20 09:02:20 +01:00
a780c7e0ff Merge pull request #179 from Fabio286/all-contributors/add-goYou
docs: add goYou as a contributor for translation
2022-01-20 08:56:33 +01:00
allcontributors[bot]
9a1bb0599f docs: update .all-contributorsrc [skip ci] 2022-01-20 07:56:07 +00:00
allcontributors[bot]
d847870f67 docs: update README.md [skip ci] 2022-01-20 07:56:06 +00:00
cd24371576 Merge pull request #177 from goYou/master
feat: add Simplified Chinese translation
2022-01-20 08:54:56 +01:00
goYou
6ef565cf07 feat: add Simplified Chinese translation 2022-01-20 01:50:18 +08:00
46b45c8ab6 fix(PostgreSQL): schema different than public not automatically selected, closes #172 2022-01-17 09:15:18 +01:00
f28531a225 build: resolved dependency conflicts 2022-01-16 11:50:35 +01:00
8fb1f0803e fix: cell copy returns "undefined" in some conditions, closes #170 2022-01-14 18:37:37 +01:00
020ce36312 chore(release): 0.4.2 2022-01-10 08:50:00 +01:00
b4545b178f feat(UI): textarea autofocus selecting a query tab, closes #166 2022-01-09 12:28:01 +01:00
d9a3eab015 perf(MySQL): support to ANSI_QUOTES sql_mode, closes #158 2022-01-05 18:23:31 +01:00
2ab49c218d Merge pull request #164 from toriphes/feat/keep-window-state
feat: keep window state
2021-12-28 19:30:51 +01:00
Giulio Ganci
8f9385d508 feat: save window state
open the main window in the last used position of the screen
2021-12-28 17:12:10 +01:00
Giulio Ganci
4e9f8d16ee feat: initial mysql import support 2021-12-28 15:30:07 +01:00
0c002918eb feat(PostgreSQL): ability to cancel queries 2021-12-26 21:13:02 +01:00
3d56ec7b49 Merge pull request #157 from Fabio286/dependabot/npm_and_yarn/eslint-plugin-promise-6.0.0
build(deps-dev): bump eslint-plugin-promise from 5.2.0 to 6.0.0
2021-12-24 18:04:58 +01:00
48c3e6afc4 perf: hash for foreign key default names 2021-12-23 11:47:17 +01:00
dependabot[bot]
50a5c8fe1e build(deps-dev): bump eslint-plugin-promise from 5.2.0 to 6.0.0
Bumps [eslint-plugin-promise](https://github.com/xjamundx/eslint-plugin-promise) from 5.2.0 to 6.0.0.
- [Release notes](https://github.com/xjamundx/eslint-plugin-promise/releases)
- [Changelog](https://github.com/xjamundx/eslint-plugin-promise/blob/development/CHANGELOG.md)
- [Commits](https://github.com/xjamundx/eslint-plugin-promise/commits)

---
updated-dependencies:
- dependency-name: eslint-plugin-promise
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-20 19:03:06 +00:00
b0d1f115c9 ci: update actions/checkout to v2 2021-12-20 09:27:36 +01:00
a59f77f618 feat(MySQL): ability to cancel queries 2021-12-19 11:59:09 +01:00
e7a1858091 fix(SQLite): exception with some fields 2021-12-16 09:16:15 +01:00
648a51efe8 Merge pull request #154 from Fabio286/all-contributors/add-wenj91
docs: add wenj91 as a contributor for code
2021-12-14 09:49:24 +01:00
38962c4807 Merge pull request #153 from wenj91/master
[TypeError: Cannot read properties of undefined (reading 'type') #152] bugfix
2021-12-14 09:48:58 +01:00
allcontributors[bot]
43e4cdd4cf docs: update .all-contributorsrc [skip ci] 2021-12-14 08:48:00 +00:00
allcontributors[bot]
91046c1ac1 docs: update README.md [skip ci] 2021-12-14 08:47:59 +00:00
文杰
63f8b9b6a1 Merge branch 'Fabio286:master' into master 2021-12-14 09:40:42 +08:00
文杰
ed476d9b5c Merge pull request #1 from wenj91:152-bugfix
[TypeError: Cannot read properties of undefined (reading 'type') #152] bugfix
2021-12-14 09:40:02 +08:00
文杰
f41d8c0480 [TypeError: Cannot read properties of undefined (reading 'type') #152] bugfix 2021-12-14 01:37:59 +00:00
e3b54a8be1 Merge pull request #151 from datlechin/master
Update vi-VN translation
2021-12-13 08:08:30 +01:00
Ngo Quoc Dat
c2c0394624 Update vi-VN translation 2021-12-13 08:48:07 +07:00
Giulio Ganci
d25c62b4da feat: delete dump file when the export is canceled 2021-11-04 23:09:28 +01:00
Giulio Ganci
8cf738bac8 fix(MySQL): export crash with large databases 2021-11-04 22:36:45 +01:00
409ed54608 perf: split the export select query to avoid running out of memory 2021-11-01 16:12:20 +01:00
d9d3bf2bc9 perf: avoid to load schema elements if already loaded in export modal 2021-11-01 14:52:45 +01:00
9e9de7b5c5 Merge branch 'master' of https://github.com/Fabio286/antares into pr/toriphes/129 2021-11-01 10:09:37 +01:00
Giulio Ganci
b2a5b40c03 feat: mysql export for trigger, views, schedulers, functions and routines 2021-10-31 17:22:59 +01:00
Giulio Ganci
0de2321920 feat: initial db export implementation 2021-10-29 12:58:37 +02:00
271 changed files with 54077 additions and 17601 deletions

View File

@@ -1,6 +1,6 @@
{
"projectName": "antares",
"projectOwner": "Fabio286",
"projectOwner": "antares-sql",
"repoType": "github",
"repoHost": "https://github.com",
"files": [
@@ -120,6 +120,88 @@
"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"
]
},
{
"login": "raliqala",
"name": "Topollo",
"avatar_url": "https://avatars.githubusercontent.com/u/30502407?v=4",
"profile": "https://github.com/raliqala",
"contributions": [
"code"
]
},
{
"login": "SmileYzn",
"name": "Cleverson",
"avatar_url": "https://avatars.githubusercontent.com/u/5851851?v=4",
"profile": "https://github.com/SmileYzn",
"contributions": [
"translation"
]
},
{
"login": "fredatgithub",
"name": "fred",
"avatar_url": "https://avatars.githubusercontent.com/u/6720055?v=4",
"profile": "https://github.com/fredatgithub",
"contributions": [
"translation"
]
},
{
"login": "xak666",
"name": "xaka_xak",
"avatar_url": "https://avatars.githubusercontent.com/u/38811437?v=4",
"profile": "https://github.com/xak666",
"contributions": [
"translation"
]
},
{
"login": "brdtheo",
"name": "Théo Billardey",
"avatar_url": "https://avatars.githubusercontent.com/u/48206778?v=4",
"profile": "https://codepen.io/theo-billardey",
"contributions": [
"translation"
]
},
{
"login": "dyaskur",
"name": "Muhammad Dyas Yaskur",
"avatar_url": "https://avatars.githubusercontent.com/u/9539970?v=4",
"profile": "http://yaskur.net",
"contributions": [
"translation",
"code"
]
},
{
"login": "jimcat8",
"name": "tianci li",
"avatar_url": "https://avatars.githubusercontent.com/u/86754294?v=4",
"profile": "https://github.com/jimcat8",
"contributions": [
"translation"
]
}
],
"contributorsPerLine": 7,

View File

@@ -1,4 +1,5 @@
node_modules
assets
out
dist
dist
build

View File

@@ -6,15 +6,23 @@
},
"extends": [
"standard",
"plugin:vue/recommended"
"plugin:@typescript-eslint/recommended",
"plugin:vue/vue3-recommended"
],
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "@babel/eslint-parser",
"parser": "@typescript-eslint/parser",
"ecmaVersion": 9,
"sourceType": "module",
"requireConfigFile": false
},
"plugins": [
"vue",
"@typescript-eslint"
],
"rules": {
"space-infix-ops": "off",
"object-curly-newline": "off",
"indent": [
"error",
3,
@@ -69,6 +77,20 @@
"max": 1
}
}
]
],
"@typescript-eslint/member-delimiter-style": [
"warn",
{
"multiline": {
"delimiter": "semi",
"requireLast": true
},
"singleline": {
"delimiter": "semi",
"requireLast": false
}
}
],
"@typescript-eslint/no-var-requires": "off"
}
}

View File

@@ -26,13 +26,16 @@ If applicable, add screenshots to help explain your problem.
**Application (please complete the following information):**
- Version [e.g. 0.14.0]
- Distribution: [e.g. exe, Linux Store, AppImage, dmg]
- App client [e.g. MySQL]
- App version [e.g. 0.5.2]
- Installation source: [e.g. exe, Linux Store, AppImage, dmg]
**Desktop (please complete the following information):**
**Environment (please complete the following information):**
- OS: [e.g. iOS]
- Version [e.g. 22]
- OS name: [e.g. Windows 11]
- OS version [e.g. 21H2]
- DB name [e.g. MariaDB]
- DB version [e.g. 10.3.34]
**Additional context**
Add any other context about the problem here.

View File

@@ -6,6 +6,8 @@
version: 2
updates:
- package-ecosystem: "npm"
allow:
- dependency-type: "production"
directory: "/"
schedule:
interval: "weekly"
interval: "monthly"

View File

@@ -1,32 +0,0 @@
name: Build/release [linux]
on: push
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v1
- 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:
github_token: ${{ secrets.github_token }}
release: ${{ startsWith(github.ref, 'refs/tags/v') }}

View File

@@ -1,32 +0,0 @@
name: Build/release [mac]
on: push
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v1
- 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:
github_token: ${{ secrets.github_token }}
release: ${{ startsWith(github.ref, 'refs/tags/v') }}

View File

@@ -1,32 +0,0 @@
name: Build/release [windows]
on: push
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v1
- 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:
github_token: ${{ secrets.github_token }}
release: ${{ startsWith(github.ref, 'refs/tags/v') }}

37
.github/workflows/build.yml vendored Normal file
View File

@@ -0,0 +1,37 @@
name: Build & release
on:
push:
tags:
- "v*"
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [macos-11, ubuntu-20.04, windows-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm i
- name: "Build"
run: npm run build
- name: Release
uses: ncipollo/release-action@v1
with:
artifacts: "build/*.AppImage,build/*.yml,build/*.deb,build/*.dmg,build/*.blockmap,build/*.zip,build/*.exe"
allowUpdates: true
draft: true
generateReleaseNotes: true

View File

@@ -0,0 +1,31 @@
name: Create artifact [LINUX]
on:
workflow_dispatch: {}
jobs:
build:
runs-on: ubuntu-20.04
steps:
- name: Check out Git repository
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: npm install & build
run: |
npm install
npm run build
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: linux-build
retention-days: 3
path: |
build
!build/*-unpacked
!build/.icon-ico

View File

@@ -0,0 +1,31 @@
name: Create artifact [MAC]
on:
workflow_dispatch: {}
jobs:
build:
runs-on: macos-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: npm install & build
run: |
npm install
npm run build
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: macos-build
retention-days: 3
path: |
build
!build/*-unpacked
!build/.icon-ico

26
.github/workflows/test-e2e-win.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Test end-to-end [WINDOWS]
on: push
jobs:
release:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [windows-latest]
steps:
- name: Check out Git repository
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm i
- name: Run tests
run: npm run test:e2e

4
.gitignore vendored
View File

@@ -1,8 +1,10 @@
.DS_Store
dist
build
misc/*
!misc/.gitkeep
node_modules
thumbs.db
NOTES.md
*.txt
package-lock.json
*.heapsnapshot

1
.nvmrc
View File

@@ -1 +0,0 @@
v16.13.0

View File

@@ -1,6 +1,7 @@
{
"extends": [
"stylelint-config-standard"
"stylelint-config-standard",
"stylelint-config-recommended-vue"
],
"fix": true,
"formatter": "verbose",
@@ -10,6 +11,7 @@
"rules": {
"at-rule-no-unknown": null,
"no-descending-specificity": null,
"font-family-no-missing-generic-family-keyword": null,
"declaration-colon-newline-after": "always-multi-line"
},
"syntax": "scss"

12
.vscode/launch.json vendored
View File

@@ -2,10 +2,9 @@
"version": "0.2.0",
"configurations": [
{
"cwd": "${workspaceFolder}",
"name": "Electron: Main",
"cwd": "${workspaceFolder}",
"port": 9222,
"protocol": "inspector",
"request": "attach",
"sourceMaps": true,
"type": "node",
@@ -18,6 +17,15 @@
"sourceMaps": true,
"type": "chrome",
"webRoot": "${workspaceFolder}"
},
{
"name": "Electron: Worker",
"cwd": "${workspaceFolder}",
"port": 9224,
"request": "attach",
"sourceMaps": true,
"type": "node",
"timeout": 1000000
}
],
"compounds": [

View File

@@ -4,7 +4,13 @@
"core",
"MySQL",
"PostgreSQL",
"SQLite"
"SQLite",
"Firebird SQL",
"Windows",
"translation",
"Linux",
"MacOS",
"deps"
],
"svg.preview.background": "transparent"
}

View File

@@ -2,6 +2,612 @@
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.7.5](https://github.com/antares-sql/antares/compare/v0.7.4...v0.7.5) (2023-02-26)
### Features
* **MySQL:** option, disabled by default, to enable table size indicators on sidebar ([313e740](https://github.com/antares-sql/antares/commit/313e7407eb1afe5d19ac49ee4b308950b48cafa8))
### Bug Fixes
* **MariaDB:** exception with event_scheduler DISABLED with MariaDB 10, fixes [#535](https://github.com/antares-sql/antares/issues/535) ([4458177](https://github.com/antares-sql/antares/commit/445817768863616ea7340c8bf62472197b73bd6e))
* single quotes not properly escaped for random generated content ([629ce63](https://github.com/antares-sql/antares/commit/629ce633294c862266db9e27ffa5c154e8fc416c))
* unable to import after a failed import, fixes [#515](https://github.com/antares-sql/antares/issues/515) ([b1fbc43](https://github.com/antares-sql/antares/commit/b1fbc43ab2f39827cb85ac7d21ac889ffc2f4c64))
### [0.7.4](https://github.com/antares-sql/antares/compare/v0.7.3...v0.7.4) (2023-02-10)
### Bug Fixes
* tables sort in sidebar ([ddb7ead](https://github.com/antares-sql/antares/commit/ddb7ead0832708713ba4bb2717661b8b93a47e3f))
### [0.7.3](https://github.com/antares-sql/antares/compare/v0.7.2...v0.7.3) (2023-02-09)
### Features
* **SQLite:** added support to INTEGER UNSIGNED ([e7e4913](https://github.com/antares-sql/antares/commit/e7e491340a037b64d6d8e538376415779d54332e))
### Bug Fixes
* longtext edit modal opens when it shouldn't, fixes [#524](https://github.com/antares-sql/antares/issues/524) ([6decba3](https://github.com/antares-sql/antares/commit/6decba316ca46106520cb4dba44409ceb4a4af75))
* select of table type stuck when editing an unknown type ([e8447e5](https://github.com/antares-sql/antares/commit/e8447e56551871a200517bdaa747ae215ad83cf4))
* **SQLite:** error with integer timestamp fields ([2b5e1e7](https://github.com/antares-sql/antares/commit/2b5e1e7b39c25f536b6139a4d01b9f7f17069ea8))
* **SQLite:** triggers disappear after editing related table, fixes [#523](https://github.com/antares-sql/antares/issues/523) ([d934ae1](https://github.com/antares-sql/antares/commit/d934ae1e6c0747698b4973d9cad217379076a6cf))
### [0.7.2](https://github.com/antares-sql/antares/compare/v0.7.1...v0.7.2) (2023-01-22)
### Features
* add copy shortcut and default copy type setting ([9aca894](https://github.com/antares-sql/antares/commit/9aca89477f1fd7b7f55f1e5c290d495c46f61d8e))
* connection info icons in footer ([ff4bc6c](https://github.com/antares-sql/antares/commit/ff4bc6c39b05a827cebde84466814cf246908208))
### Bug Fixes
* allow comments in queies, fixes [#519](https://github.com/antares-sql/antares/issues/519) ([c7ab3b7](https://github.com/antares-sql/antares/commit/c7ab3b77a22e85cee6fb93064eaad5a8e8ad9fd2))
* **SQLite:** exception saving tables without INT fields length ([0e80e82](https://github.com/antares-sql/antares/commit/0e80e823d059dfe24995b5848d88cc84235e6275))
* ssh connection closed after idle time, fixes [#425](https://github.com/antares-sql/antares/issues/425) ([6fa430a](https://github.com/antares-sql/antares/commit/6fa430adf68013a9d0a093031f56dd741bdc0299))
### [0.7.1](https://github.com/antares-sql/antares/compare/v0.7.0...v0.7.1) (2022-12-23)
### Features
* Copy rows as html table, so we can paste it to spreadsheet ([c32f463](https://github.com/antares-sql/antares/commit/c32f463ea5ac3f54cba32929f77442f1e0ba934a))
* option to disable selected query execution, closes [#477](https://github.com/antares-sql/antares/issues/477) ([1bd26ce](https://github.com/antares-sql/antares/commit/1bd26ceaa68fe66f26c76b3b60fa6eeccea91729))
### Bug Fixes
* bahasa indonesia typos ([897795d](https://github.com/antares-sql/antares/commit/897795ddbb4ade2652b0471f18288b8b3aaf0eb9))
* connection default icon not change after client change ([a6bdf69](https://github.com/antares-sql/antares/commit/a6bdf69a281c8614c41274b6dc2f3563aa89c57e))
* context submenu outside view when near the edge, fixes [#506](https://github.com/antares-sql/antares/issues/506) ([c08946e](https://github.com/antares-sql/antares/commit/c08946e932884e5f0253df2545f98315ab7e5219))
* **i18n:** add missing keys for french translation ([fd129a2](https://github.com/antares-sql/antares/commit/fd129a2ad1c3401372c9172b38f4406254d134df))
* **MySQL:** not every connection gets read-only option ([843c15e](https://github.com/antares-sql/antares/commit/843c15e428c4a0412f19a93ab05d2fcbb60da09b))
* **UI:** white background dragging connections inside folder on Linux ([dd971d7](https://github.com/antares-sql/antares/commit/dd971d70e04faf0d5b239586b12e4a9a42407433))
* white background dragging connections or tabs on Linux, fixes [#486](https://github.com/antares-sql/antares/issues/486) ([669d7e8](https://github.com/antares-sql/antares/commit/669d7e8d4d062ed5bdafe1d5cde8ec51a2f68b26))
## [0.7.0](https://github.com/antares-sql/antares/compare/v0.6.0...v0.7.0) (2022-11-30)
### Features
* **UI:** connections customization ([212b2bd](https://github.com/antares-sql/antares/commit/212b2bdba933db1af22967a057d64f41c96b9930))
* **UI:** folders customization ([72accb7](https://github.com/antares-sql/antares/commit/72accb7b0e62977dde2c82312aee5b9d025e5182))
* **UI:** folders implementation ([ece6c64](https://github.com/antares-sql/antares/commit/ece6c6401def4a9b42280f23efaa038b9ad98de8))
* **UI:** footer color based on folder color ([4fe9dfc](https://github.com/antares-sql/antares/commit/4fe9dfc4d7ca19a798b8a8a74d979ab88aebeaac))
* **UI:** new settimgbar tooltips ([6728964](https://github.com/antares-sql/antares/commit/672896414e901635c83ca037663e355a31ce013b))
### Bug Fixes
* deletion of connections inside folder ([b06bafe](https://github.com/antares-sql/antares/commit/b06bafe06c060233ebe901979b9fc4455a25cb89))
* missing sidebar data after update ([0a1f50a](https://github.com/antares-sql/antares/commit/0a1f50a9b92c9705784b93f14be40a01a78cb0da))
* **UI:** folder to folder drag glitches ([0fca70e](https://github.com/antares-sql/antares/commit/0fca70ebec1af3d594db4e1ce159e52e12224850))
* **UI:** wrong copnnection icons color with light theme ([d010d5a](https://github.com/antares-sql/antares/commit/d010d5aa8f07a5def1183567ee767fd144696ed3))
* wrong position moving elements outside folder ([7af178a](https://github.com/antares-sql/antares/commit/7af178a1e400876e6c45dbe31a198a12d29227a8))
## [0.6.0](https://github.com/antares-sql/antares/compare/v0.5.19...v0.6.0) (2022-11-18)
### Features
* **Firebird SQL:** connections pool ([76df631](https://github.com/antares-sql/antares/commit/76df6319c242ea42f93d4e5d811d96ec2c282aa8))
* **Firebird SQL:** display table content and query results ([95bb41e](https://github.com/antares-sql/antares/commit/95bb41e9db255a780aae1ae32ce4a53ee3bab20e))
* **Firebird SQL:** manual commit mode ([27566c1](https://github.com/antares-sql/antares/commit/27566c1dfae55f72d3f870c50410e5ecda256037))
* **Firebird SQL:** procedure add/edit/delete support ([ae312ef](https://github.com/antares-sql/antares/commit/ae312efbbc3a9941380477b9849bdd8edc5b9fbf))
* **Firebird SQL:** support to blob fields ([0827a04](https://github.com/antares-sql/antares/commit/0827a04d61af75b4366394e5f0289df461d02c98))
* **Firebird SQL:** support to indexes and foreign keys ([2c8509f](https://github.com/antares-sql/antares/commit/2c8509ff4173fbebeff92ab472a37edd3d80a2ac))
* **Firebird SQL:** table add/edit/delete support ([1b5cc31](https://github.com/antares-sql/antares/commit/1b5cc315dddca6b753fb6fe6e196e29441ffed79))
* **Firebird SQL:** trigger add/edit/delete support ([8e422e3](https://github.com/antares-sql/antares/commit/8e422e3f07323f388523621a05f0403a87f19e47))
* **Firebird SQL:** view add/edit/delete support ([7d1967a](https://github.com/antares-sql/antares/commit/7d1967a60977b2ce1095a37b7135f429a83f163d))
* support to text blob fields ([e6f6a02](https://github.com/antares-sql/antares/commit/e6f6a022d1a5bbc3f5303f635a2115813601c61a))
### Bug Fixes
* **Firebird SQL:** connection pool issue ([7ff8e21](https://github.com/antares-sql/antares/commit/7ff8e2149ef911a235b4a1dcc329775af1d2a72b))
* incomplete list of collations, fixes [#478](https://github.com/antares-sql/antares/issues/478) ([1c1403f](https://github.com/antares-sql/antares/commit/1c1403f58641f7b5f8a7c29fc430673ffa88f969))
* loss of precision updating BIGINT values, fixes [#467](https://github.com/antares-sql/antares/issues/467) ([d190a2d](https://github.com/antares-sql/antares/commit/d190a2dd61040d1748dfb97403f9d56015d938fe))
### [0.5.19](https://github.com/antares-sql/antares/compare/v0.5.18...v0.5.19) (2022-10-22)
### Features
* context menu option to fill cell with random values ([0a2124f](https://github.com/antares-sql/antares/commit/0a2124f2c2bdadc7c753db11d1e29f8acb9ddcac))
* uuid fill for string cells ([24edc82](https://github.com/antares-sql/antares/commit/24edc82b1be7299a09df18611b2a0ba361a6b46f))
### Bug Fixes
* app stuck inserting a random value if field length high ([440f74d](https://github.com/antares-sql/antares/commit/440f74dfc1f4942ba585b9bdae7517fe6ab04a81))
* error joining tables with different schema ([88408da](https://github.com/antares-sql/antares/commit/88408da745e45c70de977bc4270e5f61825be65f))
* **SQLite:** save boolean as integer to improve compativility, fixes [#463](https://github.com/antares-sql/antares/issues/463) ([d52b7af](https://github.com/antares-sql/antares/commit/d52b7af2978bc8beafd2d22078c72abb62e9e532))
* unable to edit text fields if value is NULL, fixes [#466](https://github.com/antares-sql/antares/issues/466) ([8621ca5](https://github.com/antares-sql/antares/commit/8621ca5333b5c51dc7a2ea1fcc0c5ec7f752a00a))
### [0.5.18](https://github.com/antares-sql/antares/compare/v0.5.17...v0.5.18) (2022-10-14)
### Features
* **PostgreSQL:** UUID random generation option on UUID fields, closes [#424](https://github.com/antares-sql/antares/issues/424) ([a521274](https://github.com/antares-sql/antares/commit/a521274d01031c1411bbbb136369802d43368089))
### Bug Fixes
* auto-scroll on sidebar not working, fixes [#447](https://github.com/antares-sql/antares/issues/447) ([dd9c089](https://github.com/antares-sql/antares/commit/dd9c089d27c61ab76d49887c7de2849cbb6e88a6))
* trackpad horizontal scroll on tabs not working properly ([ba5a1b6](https://github.com/antares-sql/antares/commit/ba5a1b68ab2d56777a5c94eede26e9bded5819e6))
### [0.5.17](https://github.com/antares-sql/antares/compare/v0.5.16...v0.5.17) (2022-09-22)
### Features
* added more editor font sizes, closes [#440](https://github.com/antares-sql/antares/issues/440) ([d114f8a](https://github.com/antares-sql/antares/commit/d114f8a65164f702b23175095e6fc2b021e0e038))
### Bug Fixes
* "run or reload" shortcut triggers on all connections open ([01f607c](https://github.com/antares-sql/antares/commit/01f607cd40c18ab0f9761b2a05705a966aaae43a))
* cant run procedures with parameters from leftbar ([efe134a](https://github.com/antares-sql/antares/commit/efe134a059700ca87333dc6e66166d6ec8d289e8))
* editor font size doesn't change on new tabs, fixes [#442](https://github.com/antares-sql/antares/issues/442) ([84168d1](https://github.com/antares-sql/antares/commit/84168d1d75460acc2c844bfece7d85f0c977e74c))
* empty definer when editing a view, fixes [#437](https://github.com/antares-sql/antares/issues/437) ([498a9b4](https://github.com/antares-sql/antares/commit/498a9b48e25ee061960f5f649c953cdaf6ff1a58))
* **MacOS:** empty options on macos menubar ([a142d3c](https://github.com/antares-sql/antares/commit/a142d3c4d77e31375dfbea148eec54ce1f635192))
### [0.5.16](https://github.com/antares-sql/antares/compare/v0.5.15...v0.5.16) (2022-08-26)
### Bug Fixes
* CTRL+Right/Left not working on text editor, closes [#427](https://github.com/antares-sql/antares/issues/427) ([ffc645b](https://github.com/antares-sql/antares/commit/ffc645ba5efb1c52670096e4f8c7f992b7335dae))
* issue updating datetime cells with null value, closes [#423](https://github.com/antares-sql/antares/issues/423) ([ebc325a](https://github.com/antares-sql/antares/commit/ebc325ae0c656dca2eb8f7544ab271beaee9b47e))
* ts exceptions ([df68114](https://github.com/antares-sql/antares/commit/df681147aaf0bfca69f3ffdc474cc1846541b1d8))
* **UI:** editor themes group not visible in select element ([9dc700e](https://github.com/antares-sql/antares/commit/9dc700e13ea65bb8c6feac4ff4ffeadd32053614))
* **UI:** wrong position of fields resizable area ([c90ab0e](https://github.com/antares-sql/antares/commit/c90ab0e8807ff30a9ab58e9aa3515cf427dd6e86))
* unable to set null or delete rows without primary key ([39326eb](https://github.com/antares-sql/antares/commit/39326eb52e038728b5419d4a8de8024c7ead3002))
### [0.5.15](https://github.com/antares-sql/antares/compare/v0.5.14...v0.5.15) (2022-08-17)
### Features
* ability to add new shortcuts ([d044a02](https://github.com/antares-sql/antares/commit/d044a02cb79a9d06aadc34cdbf6e81da84360559))
* ability to edit shortcuts ([8eb127e](https://github.com/antares-sql/antares/commit/8eb127e45838bc01ba12f0740fec077fcd975532))
* added more events in shortcuts setting ([5043faf](https://github.com/antares-sql/antares/commit/5043fafa934844ebc2f59cabcec830c6a4d5ca8e))
* delete shortcuts and restore defaults ([c22413f](https://github.com/antares-sql/antares/commit/c22413fde9dfe5501a5f220070cfe552a318c70b))
* dynamic shortcut suggestions on empty query tabs ([4df14c3](https://github.com/antares-sql/antares/commit/4df14c3693955bd7801b4b99103fca85f00f3e8c))
* list of available shortcuts in settings window ([44bb75b](https://github.com/antares-sql/antares/commit/44bb75bc60d7d31bbd99a9ba57f30fd354f7581c))
* **UI:** connection name on left bar, closes [#382](https://github.com/antares-sql/antares/issues/382) [#414](https://github.com/antares-sql/antares/issues/414) ([4887753](https://github.com/antares-sql/antares/commit/48877534d1a41d351b267c0dab925046ca984179))
* **UI:** shortcuts setting UI improved ([49b63bc](https://github.com/antares-sql/antares/commit/49b63bc6f28fc6031e6a892d0a48cd35ae2f26cd))
### Bug Fixes
* startup exception ([c50d17e](https://github.com/antares-sql/antares/commit/c50d17e82b7fd337d4037ddf646cd1a8fc765bae))
### Improvements
* improved keypress detector ([0f219cf](https://github.com/antares-sql/antares/commit/0f219cf9b796b4369c609fb0e8e3b84346a30b07))
* **translation:** updated italian translation ([c05be83](https://github.com/antares-sql/antares/commit/c05be8304f3cf299cf338f67c00184305e022919))
### [0.5.14](https://github.com/antares-sql/antares/compare/v0.5.13...v0.5.14) (2022-08-09)
### Bug Fixes
* unable to open settingbar context menu ([44eb507](https://github.com/antares-sql/antares/commit/44eb507a12bad028a4fa8a8bb0f6442a3e8dde91))
### [0.5.13](https://github.com/antares-sql/antares/compare/v0.5.12...v0.5.13) (2022-08-09)
### Features
* copy row as CSV, closes [#394](https://github.com/antares-sql/antares/issues/394) ([1c3d7aa](https://github.com/antares-sql/antares/commit/1c3d7aa30bb9c2bd900a764ee6b97960729e9263))
* new macos icon ([0bfa14e](https://github.com/antares-sql/antares/commit/0bfa14e1c90320578597df030941530b670a4131))
### Bug Fixes
* **MySQL:** error with ANSI sql_mode ([f64a12a](https://github.com/antares-sql/antares/commit/f64a12a8e9c5f764c3a692f1a032736e008058b5))
* set legacy: false ([104b7c9](https://github.com/antares-sql/antares/commit/104b7c928b9c2abfc056880f16c606a0b1fa7c67))
### [0.5.12](https://github.com/antares-sql/antares/compare/v0.5.11...v0.5.12) (2022-07-26)
### Features
* ability to copy multiple selected rows ([9551afb](https://github.com/antares-sql/antares/commit/9551afbd2d7e525c81f28e98e788b92609ce9de4))
* context menu option to duplicate a table row ([985e5d3](https://github.com/antares-sql/antares/commit/985e5d352793d1b3e1981d004b6f494bfbb049bf))
* copy row as SQL INSERT ([d3da15a](https://github.com/antares-sql/antares/commit/d3da15aa1377dcba73927047563f1d0c2d1284ca))
* execute selected query ([7890263](https://github.com/antares-sql/antares/commit/78902639ebb29a8c53f8aa0d2045c74e0646febc))
* export table content as SQL INSERT ([f3b5de3](https://github.com/antares-sql/antares/commit/f3b5de38c4abfd2c1d738e179fc22e6c8b6f9080))
### Bug Fixes
* disable ctrl+alt+(left/right) shortcut on linux ([8ecaedb](https://github.com/antares-sql/antares/commit/8ecaedbf6c2fc0dc56ff2177a87dd6ede74bdd22))
* error on schema export ([1d151e9](https://github.com/antares-sql/antares/commit/1d151e9349fd97576ccd8ef7f88ca789a1f28b65))
* issue with logger on import/export ([cb038b3](https://github.com/antares-sql/antares/commit/cb038b374a4fe85ad569e42eee7af123c925e775))
* missing defaults on insert row window ([1ead76c](https://github.com/antares-sql/antares/commit/1ead76c02889f48bd91cae702820b082ca2ff54b))
* missing table on insert new records on session restored tabs ([8c83b3f](https://github.com/antares-sql/antares/commit/8c83b3f1447354ec63b2a308db05ad4d54659aa7))
* **MySQL:** missing quoted identifier for column names in table filter, closes [#380](https://github.com/antares-sql/antares/issues/380) ([eb60899](https://github.com/antares-sql/antares/commit/eb60899e6e17879c79a7ee7108061e9aca8596f7))
* prevent ctrl+a in console ([a00c19d](https://github.com/antares-sql/antares/commit/a00c19d3003cd43d3ee6e3132728122bb2b24c97))
### [0.5.11](https://github.com/antares-sql/antares/compare/v0.5.10...v0.5.11) (2022-07-19)
### Bug Fixes
* console events disabled in production ([0b1aa3d](https://github.com/antares-sql/antares/commit/0b1aa3dd299db641df3d4c56c7ee56a187fc3ab3))
* filter persists switching temporary table tabs ([bf768c3](https://github.com/antares-sql/antares/commit/bf768c380087b65604b5b571a9858a7f07bd681d))
* unable to edit table fields content on tables with datetime fields ([91e0630](https://github.com/antares-sql/antares/commit/91e06305133c97ea02dcfdc4e739a4b0a7e7049d))
### [0.5.10](https://github.com/antares-sql/antares/compare/v0.5.9...v0.5.10) (2022-07-18)
### Features
* context menu to copy queries from console ([c21bd60](https://github.com/antares-sql/antares/commit/c21bd6075c1203607c05e45b76233d57e3008190))
* Ctrl+PgUp & Ctrl+PgDn to navigate between tabs ([abf8298](https://github.com/antares-sql/antares/commit/abf829867e567354e534cff3e02a6d43f4c7a262))
* field names suggestion for tables in the query ([b71f04e](https://github.com/antares-sql/antares/commit/b71f04e5aa3c37eaa160dfbc76d1b84789e3543e))
* initial console implementation ([6a6f43a](https://github.com/antares-sql/antares/commit/6a6f43a718561e0abd2cb89048b7fe45d08736ae))
* ipc event channel to send logs to renderer ([f12a04b](https://github.com/antares-sql/antares/commit/f12a04b0524f1172334c89afeb27675c19ff68d2))
* open/close console on single connection ([44647f5](https://github.com/antares-sql/antares/commit/44647f5b5508965bf5a7264add89e175c725e877))
### Bug Fixes
* exception on QueryEditor with null modelValue ([9bc9adb](https://github.com/antares-sql/antares/commit/9bc9adb7cff19b86a99491d968485a4cd7b47b99))
* fields content language detection not working properly ([a91fa8f](https://github.com/antares-sql/antares/commit/a91fa8ff54bbf1f8475666efd3a268a3a4f07f0c))
* **Linux:** ctrl+space shortcut not working ([ed3d35f](https://github.com/antares-sql/antares/commit/ed3d35f1319a1e2edcb8104f2045a71b9e9754a2))
* unable to delete by select all in left bar search, closes [#368](https://github.com/antares-sql/antares/issues/368) ([7725faf](https://github.com/antares-sql/antares/commit/7725fafe852479720fa619ced0970f2fa0099191))
* unable to update data on tables missing primary or unique key ([e0946f0](https://github.com/antares-sql/antares/commit/e0946f04f792d25c187ea56d4714bdacc016ada3))
### Improvements
* improved resize of text editor resizing console height ([3f9e6d8](https://github.com/antares-sql/antares/commit/3f9e6d85ca445eea1028effa32418eee4980f87d))
* **UI:** improved visibility of explore bar tooltips ([f312cf5](https://github.com/antares-sql/antares/commit/f312cf5f855deddd562c26d1835f78d16499b93b))
### [0.5.9](https://github.com/antares-sql/antares/compare/v0.5.8...v0.5.9) (2022-07-06)
### Features
* ability to pin/unpin and delete connections from the "all connections" modal ([8e70570](https://github.com/antares-sql/antares/commit/8e705706aecc5c9790329e63e61a1c02fa5d0342))
* connections sorted by last usage by default and option to pin them ([36e98e0](https://github.com/antares-sql/antares/commit/36e98e0742657e25df7768aa5b3b7cb350df5509))
* ctrl/cmd+space to open all connections modal ([a9a4344](https://github.com/antares-sql/antares/commit/a9a4344a71cc0f8f156b839733f6ddc200a26268))
* modal with all connections ([a703dcc](https://github.com/antares-sql/antares/commit/a703dcc53eb920117bc346a3c21f0c729c0ad96d))
* option to disable scratchpad ([56b0a48](https://github.com/antares-sql/antares/commit/56b0a4815c6f54eef164d849f6ca25af1e142b16))
* search form in all connections modal ([ec5ab73](https://github.com/antares-sql/antares/commit/ec5ab73b19d99e9971ae87e5f0a8d1bd1c34ef00))
### Bug Fixes
* error on export schema ([cf9c7c6](https://github.com/antares-sql/antares/commit/cf9c7c600aa915cef1ec3777866badb7ab1312ee))
* missing option for untrusted ssl connection on connections edit panel ([71a5b5c](https://github.com/antares-sql/antares/commit/71a5b5c8285fb777c43e7f6516006bfe9f52591c))
### Improvements
* **UI:** improved focus visibility for buttons ([d2eb31a](https://github.com/antares-sql/antares/commit/d2eb31a63d612323f8738eded1e1ce7b23554001))
### [0.5.8](https://github.com/antares-sql/antares/compare/v0.5.7...v0.5.8) (2022-07-02)
### Features
* add max visible options prop ([067a6f3](https://github.com/antares-sql/antares/commit/067a6f350757c1e6b4df51f801ae832b47bd3484))
* context shortcut to disconnect from left bar ([e97da37](https://github.com/antares-sql/antares/commit/e97da3710385690b85391938e40145a1591bc2e8))
* **MySQL:** option to disable foreign key checks when empty a table ([902c29f](https://github.com/antares-sql/antares/commit/902c29ffa551bc3489fa1d9136ee926d135ea14f))
### Bug Fixes
* connection string field doesn't appear switching to postgre when editing a connection ([6573fe6](https://github.com/antares-sql/antares/commit/6573fe69aca2b99c7a700879fb0d0930e864cbe6))
* ctrl+a on results doesn't work properly ([5f57a9f](https://github.com/antares-sql/antares/commit/5f57a9f60d281e24e5bee4330c081fa5d8651b36))
* double context menu on table settings rows ([91d0735](https://github.com/antares-sql/antares/commit/91d0735a5f4861bc6ad13b9285ea7a9bd7be9538))
* editor gutter pin not working ([cfd82c8](https://github.com/antares-sql/antares/commit/cfd82c8f419952879b386187eb146847098263fe))
* error on modals missing focusable elements ([7702ca0](https://github.com/antares-sql/antares/commit/7702ca025fcae6209ae3851d0ccd25579f93e243))
* exception on new scheduler tab ([a45d76e](https://github.com/antares-sql/antares/commit/a45d76e8b4ecdecf53438fe174f61ea32f4e10ac))
* focus goes outside modals with tab key navigation ([e42c424](https://github.com/antares-sql/antares/commit/e42c424a13a6901414a1a1c4e2f68cb4ddef7d59))
* reactivity problem on BaseVirtualScroll component ([45b2eb2](https://github.com/antares-sql/antares/commit/45b2eb2934b9f7a08f379ad4d7a44b1c89585449))
* result table cells/rows not loses focus clicking outside ([0a3a482](https://github.com/antares-sql/antares/commit/0a3a4827dd75539666fa2c827415af3bfa224543))
* **UI:** wrong tables scrollable height after switching tabs ([8f01740](https://github.com/antares-sql/antares/commit/8f01740475ea6d5d9b5eefabdbf27099df76f2cf))
* **Windows:** white window buttons with dark theme ([a80d227](https://github.com/antares-sql/antares/commit/a80d22740045a61fd14fd5da401c0d123d54f4de))
* **Windows:** Windows 7 style window frame at startup ([93ce619](https://github.com/antares-sql/antares/commit/93ce619782d58cfb8fb1ecce2ca2137a61ec6181))
### [0.5.7](https://github.com/antares-sql/antares/compare/v0.5.4...v0.5.7) (2022-06-19)
### Features
* added dropdown animation ([5398964](https://github.com/antares-sql/antares/commit/539896419064db9127f6a72acdbb11af2c4aa60a))
* dynamic app window title ([0024269](https://github.com/antares-sql/antares/commit/00242697a102f82dd0c731a3529c984fbdf83b3e))
* hotkeys to navigate forward or backward between tabs ([d3b9e08](https://github.com/antares-sql/antares/commit/d3b9e08446708654b3c6fad565b734d93effe683))
* hotkeys to navigate inside a table resultset ([49abd1e](https://github.com/antares-sql/antares/commit/49abd1ea7f5ec368e9a9201f8fd5b6520c4bd0a8))
* **translation:** russian translation, closes [#266](https://github.com/antares-sql/antares/issues/266) ([9082960](https://github.com/antares-sql/antares/commit/9082960310573a6e4d14bfbe82ed2eb1489f308d))
* **UI:** BaseSelect disabled state ([2b436d8](https://github.com/antares-sql/antares/commit/2b436d8613a1e3dff55d73adbddf5d2cd2452f27))
* **UI:** BaseSelect in table filters ([a037d0c](https://github.com/antares-sql/antares/commit/a037d0cc0148444e8e6c5b87c79f6ba9c2a6f0fe))
* **UI:** BaseSelect option list scrolls automatically using up/down keys ([0043d07](https://github.com/antares-sql/antares/commit/0043d077081fc49724722a5d5a74986d990c539d))
* **UI:** BaseSelect small variant ([5582a12](https://github.com/antares-sql/antares/commit/5582a12bbfade75dbcc7f9d71ada7190ed08d3c2))
* **UI:** BaseSelect supports disabled options ([f7e04d6](https://github.com/antares-sql/antares/commit/f7e04d633340a53420ce1c434e906c9434620e6e))
* **UI:** BaseSelect supports option groups ([1869e6a](https://github.com/antares-sql/antares/commit/1869e6a1482daf9381d9ac2244bf0aeffa758edc))
* **UI:** ForeignKeySelect implements BaseSelect component ([302c664](https://github.com/antares-sql/antares/commit/302c66457deeb50facf4735291640fcf48b78f66))
* **UI:** initial BaseSelect integration ([22622df](https://github.com/antares-sql/antares/commit/22622df2cfcb71054c6f6110b7ad9d4f635553dc))
* **UI:** new BaseSelect component ([745d551](https://github.com/antares-sql/antares/commit/745d551cc9253eae4e39e5d3406ceee051a7d6c1))
* **UI:** select tab replace with BaseSelect component ([42bc919](https://github.com/antares-sql/antares/commit/42bc9196ffc2f64b77f9cb42136255fc74815034))
### Bug Fixes
* empty query tab schema select if no schema selected ([31b7999](https://github.com/antares-sql/antares/commit/31b7999bba5d115913d42087614b9888bc761068))
* exception on app start setting window title ([5b33419](https://github.com/antares-sql/antares/commit/5b33419b6421d7d198a978e79e22d0a76306cdb4))
* fields sorting in table setting tabs ([77d9cac](https://github.com/antares-sql/antares/commit/77d9cac092fbb806810c3463ca066395fcab5307))
* inline field update not working with tables missing primary key ([caf776b](https://github.com/antares-sql/antares/commit/caf776bd55606c793c9763c204aa9f05d1feb27f))
* **Linux:** setting bar tooltip position ([6bad032](https://github.com/antares-sql/antares/commit/6bad032f0d1094736f651b6c06a60d2a0df36c98))
* main process not closed after window close on some conditions ([23acf00](https://github.com/antares-sql/antares/commit/23acf00def77b5662e48b84591a31760737774a7))
* **PostgreSQL:** idle timeout disabled ([a082514](https://github.com/antares-sql/antares/commit/a082514f88040c7e0ffdf4e8357bab45370a4c39))
* query tab content disappears reordering or closing other tabs, closes [#261](https://github.com/antares-sql/antares/issues/261) ([c5baf2b](https://github.com/antares-sql/antares/commit/c5baf2b0d379fdd28ee8cb907628bbfca940e2f6))
* reload tab content on tab sort ([d214c1f](https://github.com/antares-sql/antares/commit/d214c1f35ba231a8a01dbe8c0faad07d4b337752))
* selected foreign key value not visible in the insert row modal ([cba2ce2](https://github.com/antares-sql/antares/commit/cba2ce2e37cedbf0b242cc474b37bf052009ae62))
* **SQLite:** unable to insert rows with TEXT fields ([a7d5e19](https://github.com/antares-sql/antares/commit/a7d5e1973cd59d7d0ef1e74bdcf44d87fba43559))
* SSH tunnel connection error with private key, closes [#260](https://github.com/antares-sql/antares/issues/260) ([c826888](https://github.com/antares-sql/antares/commit/c826888b0dd0908958a4f727ddfa642e846269cf))
* **UI:** BaseSelect keyboard navigation ([7c45203](https://github.com/antares-sql/antares/commit/7c452036368fa0db6b9cde7c35e60a8e57bfece7))
* **UI:** BaseSelect style ([71b0736](https://github.com/antares-sql/antares/commit/71b0736d0ddbd599ab41cde0a6b0823e2bb7da2f))
* **UI:** select closes clicking on scrollbar ([8870304](https://github.com/antares-sql/antares/commit/8870304c15346257a90193807b9ae07c1393e3e2))
* unable to add new table fields ([ee623b0](https://github.com/antares-sql/antares/commit/ee623b0a0f121df0ac53d49d8be437c76ddb8539))
### Improvements
* improved precision of MariaDB or MySQL auto detection ([26aad51](https://github.com/antares-sql/antares/commit/26aad519df6ea1bbc7dffbf540193a7b2ed9ae2a))
* **Linux:** title bar improvements ([85cec05](https://github.com/antares-sql/antares/commit/85cec05f7037a1339ee223554cf127693a527aa1))
* **UI:** max height for query text area increased ([5d5f1da](https://github.com/antares-sql/antares/commit/5d5f1da97b9adfa743197d8fa0bbb6addd565a7a))
* **Windows:** title bar improvements ([5fa8bf3](https://github.com/antares-sql/antares/commit/5fa8bf38e433ef2fb31bcb893cd9e75549bd6a49))
### [0.5.6](https://github.com/antares-sql/antares/compare/v0.5.4...v0.5.6) (2022-06-02)
### Bug Fixes
* empty query tab schema select if no schema selected ([31b7999](https://github.com/antares-sql/antares/commit/31b7999bba5d115913d42087614b9888bc761068))
* inline field update not working with tables missing primary key ([caf776b](https://github.com/antares-sql/antares/commit/caf776bd55606c793c9763c204aa9f05d1feb27f))
* **SQLite:** unable to insert rows with TEXT fields ([a7d5e19](https://github.com/antares-sql/antares/commit/a7d5e1973cd59d7d0ef1e74bdcf44d87fba43559))
* **UI:** select closes clicking on scrollbar ([8870304](https://github.com/antares-sql/antares/commit/8870304c15346257a90193807b9ae07c1393e3e2))
### Improvements
* improved precision of MariaDB or MySQL auto detection ([26aad51](https://github.com/antares-sql/antares/commit/26aad519df6ea1bbc7dffbf540193a7b2ed9ae2a))
### [0.5.5](https://github.com/antares-sql/antares/compare/v0.5.4...v0.5.5) (2022-05-24)
### Features
* added dropdown animation ([5398964](https://github.com/antares-sql/antares/commit/539896419064db9127f6a72acdbb11af2c4aa60a))
* **translation:** russian translation, closes [#266](https://github.com/antares-sql/antares/issues/266) ([9082960](https://github.com/antares-sql/antares/commit/9082960310573a6e4d14bfbe82ed2eb1489f308d))
* **UI:** BaseSelect disabled state ([2b436d8](https://github.com/antares-sql/antares/commit/2b436d8613a1e3dff55d73adbddf5d2cd2452f27))
* **UI:** BaseSelect in table filters ([a037d0c](https://github.com/antares-sql/antares/commit/a037d0cc0148444e8e6c5b87c79f6ba9c2a6f0fe))
* **UI:** BaseSelect option list scrolls automatically using up/down keys ([0043d07](https://github.com/antares-sql/antares/commit/0043d077081fc49724722a5d5a74986d990c539d))
* **UI:** BaseSelect small variant ([5582a12](https://github.com/antares-sql/antares/commit/5582a12bbfade75dbcc7f9d71ada7190ed08d3c2))
* **UI:** BaseSelect supports disabled options ([f7e04d6](https://github.com/antares-sql/antares/commit/f7e04d633340a53420ce1c434e906c9434620e6e))
* **UI:** BaseSelect supports option groups ([1869e6a](https://github.com/antares-sql/antares/commit/1869e6a1482daf9381d9ac2244bf0aeffa758edc))
* **UI:** ForeignKeySelect implements BaseSelect component ([302c664](https://github.com/antares-sql/antares/commit/302c66457deeb50facf4735291640fcf48b78f66))
* **UI:** initial BaseSelect integration ([22622df](https://github.com/antares-sql/antares/commit/22622df2cfcb71054c6f6110b7ad9d4f635553dc))
* **UI:** new BaseSelect component ([745d551](https://github.com/antares-sql/antares/commit/745d551cc9253eae4e39e5d3406ceee051a7d6c1))
* **UI:** select tab replace with BaseSelect component ([42bc919](https://github.com/antares-sql/antares/commit/42bc9196ffc2f64b77f9cb42136255fc74815034))
### Bug Fixes
* **PostgreSQL:** idle timeout disabled ([a082514](https://github.com/antares-sql/antares/commit/a082514f88040c7e0ffdf4e8357bab45370a4c39))
* query tab content disappears reordering or closing other tabs, closes [#261](https://github.com/antares-sql/antares/issues/261) ([c5baf2b](https://github.com/antares-sql/antares/commit/c5baf2b0d379fdd28ee8cb907628bbfca940e2f6))
* SSH tunnel connection error with private key, closes [#260](https://github.com/antares-sql/antares/issues/260) ([c826888](https://github.com/antares-sql/antares/commit/c826888b0dd0908958a4f727ddfa642e846269cf))
* **UI:** BaseSelect keyboard navigation ([7c45203](https://github.com/antares-sql/antares/commit/7c452036368fa0db6b9cde7c35e60a8e57bfece7))
* **UI:** BaseSelect style ([71b0736](https://github.com/antares-sql/antares/commit/71b0736d0ddbd599ab41cde0a6b0823e2bb7da2f))
### Improvements
* **UI:** max height for query text area increased ([5d5f1da](https://github.com/antares-sql/antares/commit/5d5f1da97b9adfa743197d8fa0bbb6addd565a7a))
### [0.5.4](https://github.com/antares-sql/antares/compare/v0.5.3...v0.5.4) (2022-05-10)
### Bug Fixes
* app blocked by BIT fields with no default, closes [#256](https://github.com/antares-sql/antares/issues/256) ([e62f280](https://github.com/antares-sql/antares/commit/e62f280528edb0ff4550ee75038ea216e81e4f10))
* file upload input not working ([58611bf](https://github.com/antares-sql/antares/commit/58611bf07f343e6899a7446bfcd1247b0c75fc7f))
* SSH tunnel not working ([6d61518](https://github.com/antares-sql/antares/commit/6d6151814e5006935d493b9b83dbda1aa5b35391))
* unable to insert auto-generated datetime fields ([ff27244](https://github.com/antares-sql/antares/commit/ff272440bdc2a7fe699e04f8809bd5af8f9529c0))
### Improvements
* **UI:** left alignment for numbers in result tables, closes [#249](https://github.com/antares-sql/antares/issues/249) ([e02565c](https://github.com/antares-sql/antares/commit/e02565c0d9bb63efa76a79f38e3ed3586a30ad1c))
### [0.5.3](https://github.com/antares-sql/antares/compare/v0.5.2...v0.5.3) (2022-05-08)
### Features
* default open schema if only one present ([0fa22fb](https://github.com/antares-sql/antares/commit/0fa22fbe72fd4e3b2cfff6fc1847347f69fafda6))
### Bug Fixes
* can not use vue teleport with props as root element ([88eb9f7](https://github.com/antares-sql/antares/commit/88eb9f7ab80c407ec6517206c27cce715c41eb24))
* importer webpack config ([f82db96](https://github.com/antares-sql/antares/commit/f82db96f34579c5f5f0c025ba82aff13047eb045))
* importer webpack config ([b4d9821](https://github.com/antares-sql/antares/commit/b4d9821300991bf000846ae38ed18d79564db67b))
* LIKE operator in table filter not properly working, closes [#242](https://github.com/antares-sql/antares/issues/242) ([eb1afed](https://github.com/antares-sql/antares/commit/eb1afed108d97e2acb7ea5279aabd582014c3c58))
* locale change ([6af0c33](https://github.com/antares-sql/antares/commit/6af0c33461dfab868bca757e55ae62e6c6094c6c))
* missing storeToRefs imports ([ff8bb45](https://github.com/antares-sql/antares/commit/ff8bb45d6d19303b2e7701639d22e52e4ae2976c))
* missing tabs uid ([18b66b5](https://github.com/antares-sql/antares/commit/18b66b50323e69ed9d0090a4cbbe0ada9e10838d))
* **MySQL:** creating temporary tables on export to overcome view dependency errors ([e4c5d9b](https://github.com/antares-sql/antares/commit/e4c5d9b404c2b20cf113607a80ee928b810e6f05))
* **MySQL:** support to ANSI_QUOTES mode not working, closes [#243](https://github.com/antares-sql/antares/issues/243) ([9fcc7d1](https://github.com/antares-sql/antares/commit/9fcc7d1cefc3c035a63e843616c3138c772037f1))
* prevents query tabs targets previous schema if not in explorebar, closes [#236](https://github.com/antares-sql/antares/issues/236) ([5e4abd3](https://github.com/antares-sql/antares/commit/5e4abd3e81d70bcb9b3a897d38d6f8ec3ff0706b))
* query editor table fields suggestion ([e9dedfa](https://github.com/antares-sql/antares/commit/e9dedfaf3203f5621e54fd707003a47e6e5a5c4d))
* **SQLite:** tables with sqlite in name not visible, closes [#239](https://github.com/antares-sql/antares/issues/239) ([690cdcb](https://github.com/antares-sql/antares/commit/690cdcb2eb1c7bf514271000c31211d1c0b33e54))
* unable to add parameters to new routines/functions ([350d536](https://github.com/antares-sql/antares/commit/350d53642e2491fd2dedbbf999579ba9c9bc59a0))
* unable to disconnect from database ([47e1f27](https://github.com/antares-sql/antares/commit/47e1f27bb83b99288157185ad8b62d190a9e7881))
* unable to set an empty string as field default ([bfdb463](https://github.com/antares-sql/antares/commit/bfdb463390453a55963af29ef0e7cd3aea26f4cf))
* undefined uid variable in the setting bar ([3cca3ed](https://github.com/antares-sql/antares/commit/3cca3ed2b31c5763794c52cce34ccba1e848efe2))
* various warnings and exceptions ([c50cbc5](https://github.com/antares-sql/antares/commit/c50cbc577f667c17ba676960cf2c840d24366c80))
* verbose devtool loggin with missing sourcemap ([1174bab](https://github.com/antares-sql/antares/commit/1174bab0cc895c4e294804d810b0789166602725))
* wrong path module importation ([472fa6f](https://github.com/antares-sql/antares/commit/472fa6f4300b7e3fbf8c8079a548ca34d941f5fb))
* wrong path module importation ([9a0f982](https://github.com/antares-sql/antares/commit/9a0f98272342d201e9bc979d5bc5768cfd20f3fb))
### [0.5.2](https://github.com/antares-sql/antares/compare/v0.5.1...v0.5.2) (2022-04-10)
### Features
* **core:** option to allow untrusted SSL connections ([6cc098c](https://github.com/antares-sql/antares/commit/6cc098c6f02fb52cc71c0141431ab75f12744a1c))
* french translation updated, closes [#222](https://github.com/antares-sql/antares/issues/222) ([796f61b](https://github.com/antares-sql/antares/commit/796f61bf2feab0da515901e2137dc7bf04371d7d))
* **PostgreSQL:** export functions and procedures ([a8ca8f2](https://github.com/antares-sql/antares/commit/a8ca8f2f76ab36c4afe84d602709386315f4b7d1))
* **PostgreSQL:** export tables ([a67071e](https://github.com/antares-sql/antares/commit/a67071e28470bcbd0ec26780bb86f3c65750ded8))
* **PostgreSQL:** export triggers ([42376b4](https://github.com/antares-sql/antares/commit/42376b4bc6dd8b630402d09b026d9fbc0b8646bb))
* **PostgreSQL:** export user-defined types before tables ([bb02479](https://github.com/antares-sql/antares/commit/bb02479b71bf75a6e69e28af57c5fe213d3f30bc))
* **PostgreSQL:** export views ([86f011f](https://github.com/antares-sql/antares/commit/86f011f34fec9d6829bce324493fea888a863ffc))
* **PostgreSQL:** sql dump importer ([6086ca4](https://github.com/antares-sql/antares/commit/6086ca4a80b9ad6a07086446253d781f052d3abc))
### Bug Fixes
* **PostgreSQL:** wrong values exporting table content ([0f9c991](https://github.com/antares-sql/antares/commit/0f9c991f539560913fa0e9361a16e6448a066a27))
* ssh tunnel not properly working, closes [#220](https://github.com/antares-sql/antares/issues/220) ([026d74c](https://github.com/antares-sql/antares/commit/026d74c8c88c605a3c8c963c211078f5b3dcfda1))
### Improvements
* **PostgreSQL:** improved dump file ([408dded](https://github.com/antares-sql/antares/commit/408ddeda5634ab6bf41eff760271669170b60eb6))
* **PostgreSQL:** improved views exportation ([638a88a](https://github.com/antares-sql/antares/commit/638a88a1fb35c048ff4c6d120aaaef831c846f58))
### [0.5.1](https://github.com/Fabio286/antares/compare/v0.5.0...v0.5.1) (2022-03-25)
### Features
* export database as zip sql file ([8f3efab](https://github.com/Fabio286/antares/commit/8f3efabb6962c55c23a43c8da1433185dbc3fb41))
* **UI:** option to disable blur effects, closes [#209](https://github.com/Fabio286/antares/issues/209) ([e9079ad](https://github.com/Fabio286/antares/commit/e9079adb25ec28e9546acd54bc2565b8d6e28120))
### Bug Fixes
* numeric scale displayed on non decimal fields ([db628f7](https://github.com/Fabio286/antares/commit/db628f77226b161c3df31b7450b92a6e58754ab7))
* **UI:** connection buttons out of screen on small displays, closes [#213](https://github.com/Fabio286/antares/issues/213) ([f12e6a9](https://github.com/Fabio286/antares/commit/f12e6a96dd66140b06c55eda775af48a666627dd))
## [0.5.0](https://github.com/Fabio286/antares/compare/v0.4.4...v0.5.0) (2022-03-12)
### Features
* delete dump file when the export is canceled ([d25c62b](https://github.com/Fabio286/antares/commit/d25c62b4da9480e040d0bfac8b76732a4c69a5f1))
* initial db export implementation ([0de2321](https://github.com/Fabio286/antares/commit/0de232192076d1de827424c593ac9dff63903531))
* initial mysql import support ([4e9f8d1](https://github.com/Fabio286/antares/commit/4e9f8d16ee3c204d5f0c2bed081206f8b38207a6))
* mysql export for trigger, views, schedulers, functions and routines ([b2a5b40](https://github.com/Fabio286/antares/commit/b2a5b40c03d56bced5a7968c3454f36060e56dd0))
* **MySQL:** enhance export characters escaping ([3be826d](https://github.com/Fabio286/antares/commit/3be826df4b02ff0df0aa922d96755b31b7155784))
* **MySQL:** support to multi spatial fields export ([4be55f3](https://github.com/Fabio286/antares/commit/4be55f3fe9bb48324b780734762f2ff6da2ccb61))
* **PostgreSQL:** :sparkles: Postgress connection string feature for local and server connection string ([6305752](https://github.com/Fabio286/antares/commit/6305752ad117cc29c04bce3ce3df321f743cdc44))
* **PostgreSQL:** :sparkles: Postgress connection string feature for local and server connection string ([f4a63ea](https://github.com/Fabio286/antares/commit/f4a63eae2aca2a84647a5027137614950aef1eac))
* **UI:** auto-refresh schema at the end of the import process ([abf2b92](https://github.com/Fabio286/antares/commit/abf2b92e6e66b6668e698c5addf4e3c00ae5157b))
* **UI:** better real-time import stats ([a6f5645](https://github.com/Fabio286/antares/commit/a6f5645a226454cc2c415311ac321ba3d4db4454))
* **UI:** toggle tables checkbox by column on export modal ([1c4d5b0](https://github.com/Fabio286/antares/commit/1c4d5b05b3f94b3e7bef930aa7f89bdaa596c0b9))
### Bug Fixes
* **MySQL:** exception exporting empty procedures/functions ([ee415da](https://github.com/Fabio286/antares/commit/ee415da127d6d0de95aac901a2a01af863736344))
* **MySQL:** export crash with large databases ([8cf738b](https://github.com/Fabio286/antares/commit/8cf738bac85698fddd0504eef7844279e8c11f44))
* **MySQL:** missing functions and procedures definer escapes on exporter ([f0351e5](https://github.com/Fabio286/antares/commit/f0351e5b94830f9f52256096c2601b0ca9cd811d))
* **MySQL:** missing initial delimiter for exported procedures ([1a9fc37](https://github.com/Fabio286/antares/commit/1a9fc3728580f789727256d7893ca4bb90c16a50))
* **MySQL:** procedures exportation ([4276586](https://github.com/Fabio286/antares/commit/4276586e1141500401ff1ab570b29e485f459987))
* sql parser hangs during import ([7a6bd8b](https://github.com/Fabio286/antares/commit/7a6bd8bdbd69e3b5fe265d0bb0be844699dd77c2))
* wrong schema and table size on explore bar ([4479a96](https://github.com/Fabio286/antares/commit/4479a9600b5e59ef1bcf9135d661b4d7900a4bde))
* wrong soft sort algorithm for numeric fields, closes [#199](https://github.com/Fabio286/antares/issues/199) ([763be85](https://github.com/Fabio286/antares/commit/763be8532d2b61d0b4d45e72343f6a2e5fee1db9))
### Improvements
* avoid to load schema elements if already loaded in export modal ([d9d3bf2](https://github.com/Fabio286/antares/commit/d9d3bf2bc9d39ce8eec5dffbecbf767fbcf47782))
* **MySQL:** import performance improvement ([f444746](https://github.com/Fabio286/antares/commit/f444746f465ed0e8bd2e4c007faf17e167814278))
* **MySQL:** import tasks managed with async queue ([bbe13f2](https://github.com/Fabio286/antares/commit/bbe13f27dc29f997898f8c13f36b5d582770b21d))
* **MySQL:** improved several field types support on exporter ([1990d9a](https://github.com/Fabio286/antares/commit/1990d9a3d441f0e2075ac7e893d5b166275c48c0))
* **MySQL:** prevent memory leak on large dump import ([f3759b6](https://github.com/Fabio286/antares/commit/f3759b65411a40d92b98208176cdf8e6dd8230ce))
* **PostgreSQL:** :zap: Postgres connection update, better error handling and connection string accommodation. ([330a80f](https://github.com/Fabio286/antares/commit/330a80fe70b81f466f5e883029f42087b4b5c411))
* split the export select query to avoid running out of memory ([409ed54](https://github.com/Fabio286/antares/commit/409ed54608ad402b63fcc26a6e724bc447ba89d2))
* use fork() for the export process ([748d449](https://github.com/Fabio286/antares/commit/748d44977e76c6c8d6344df52e8e3ccfab84f670))
* use fork() for the import process ([573ac6d](https://github.com/Fabio286/antares/commit/573ac6d42ef833f250d102e5b30ae6cf5877f330))
### [0.4.4](https://github.com/Fabio286/antares/compare/v0.4.3...v0.4.4) (2022-02-27)
### Features
* execution notification for ROLLBACK and COMMIT ([76743e8](https://github.com/Fabio286/antares/commit/76743e8f7c02b824cb21540bfbcbe66ba43de8fa))
* **MySQL:** manual commit mode ([4ed2f9a](https://github.com/Fabio286/antares/commit/4ed2f9a93937b4293436a64318b7d6ae3a0d93c2))
* **PostgreSQL:** manual commit mode ([d81e091](https://github.com/Fabio286/antares/commit/d81e0911ab82fb75745ab11e67e867a00d8ac273))
* reminder for uncommitted changes closing a tab ([5bfff64](https://github.com/Fabio286/antares/commit/5bfff649e92f6fe5aba4b16aa4c8d5a5a70b31b2))
* **SQLite:** manual commit mode ([7dcd444](https://github.com/Fabio286/antares/commit/7dcd4441c49fafc0f47e12c2129708fe1092e1a4))
### Bug Fixes
* bigint support, closes [#197](https://github.com/Fabio286/antares/issues/197) ([b703955](https://github.com/Fabio286/antares/commit/b7039553ccaac4fd59e521530c4a053922854130))
* **MySQL:** default value not displayed for DECIMAL fields ([fa3f3e1](https://github.com/Fabio286/antares/commit/fa3f3e1fd8101f19f18df71e90d60fd37cdddaee))
* zero-padded bit fields beyond length ([265f28b](https://github.com/Fabio286/antares/commit/265f28b4d94cde4608a1d6d3d306824134808ec2))
### [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)

133
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,133 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
fabio286@gmail.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -2,7 +2,7 @@
Antares SQL is an application based on [Electron.js](https://www.electronjs.org/) that uses [Vue.js](https://vuejs.org/) and [Spectre.css](https://picturepan2.github.io/spectre/) as frontend frameworks.
For the build process it takes advantage of [electron-builder](https://www.electron.build/).
This application uses [Vuex](https://vuex.vuejs.org/) as application state manager and [electron-store](https://github.com/sindresorhus/electron-store) to save the various settings on disc.
This application uses [Pinia🍍](https://pinia.vuejs.org/) as application state manager and [electron-store](https://github.com/sindresorhus/electron-store) to save the various settings on disc.
This guide aims to provide useful information and guidelines to everyone wants to contribute with this open-source project.
For every other question related to this project please [contact me](https://github.com/Fabio286).
@@ -14,7 +14,7 @@ The main files of the application are located inside `src` folder and are groupp
This folder contains small libraries, classes and objects. The purpose of `common` folder is to group together utilities used by **renderer** and **main** processes.
Noteworthy is the `customizations` folder that contains clients related customizations. Those settings are merged with `default.js` that lists every option.
Client related customizations are stored on Vuex and can be accessed by `customizations` property of current workspace object, or importing `common/customizations`.
Client related customizations are stored on Pinia and can be accessed by `customizations` property of current workspace object, or importing `common/customizations`.
An use case of customizations object can be the following:
@@ -44,8 +44,7 @@ In this folder is located the structure of Vue frontend application.
## Build
The command to build Antares SQL locally is `npm run build:local`.
`build` command (without `:local`) is used exclusively by the GitHub Action.
The command to build Antares SQL locally is `npm run build`.
## Conventions
@@ -62,12 +61,6 @@ The command to build Antares SQL locally is `npm run build:local`.
- [Order of words in component names](https://vuejs.org/v2/style-guide/#Order-of-words-in-component-names-strongly-recommended).
- **kebab-case** in templates for property and event names.
### Vuex
- **snake_case** for state names.
- **camelCase** for getter and action names.
- **SNAKE_CASE (all caps)** for mutation names.
### Code Style
The project includes [ESlint](https://eslint.org/) and [StyleLint](https://stylelint.io/) config files with style rules. I recommend to set the lint on-save option in your code editor.

View File

@@ -12,13 +12,14 @@
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, 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.
**At the moment this application is in development state, many features will come in future updates**, and supports only MySQL/MariaDB, PostgreSQL, SQLite and Firebird SQL.
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.
🔗 If you are curious to try Antares you can download and install the [latest release](https://github.com/Fabio286/antares/releases/latest).
👁 To stay tuned for new releases [follow Antares SQL](https://twitter.com/AntaresSQL) on Twitter.
🌟 Don't forget to **leave a star** if you appreciate this project.
🌟 Don't forget to **leave a star** if you appreciate this project.
🗳️ Poll: **[Which is the main OS you use Antares on?](https://github.com/antares-sql/antares/discussions/379)**
## Current key features
@@ -31,29 +32,30 @@ 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.
- Import and export database dumps.
- Customizable keyboard shortcuts.
- Dark and light theme.
- Editor themes.
- Scratchpad.
- Secure password storage.
## Philosophy
Why are we developing an SQL client when there are a lot of them on the market?
The main goal is to develop a totally free, full featured, cross platform and open source alternative, empowered by JavaScript's ecosystem.
A modern application created with minimalism and semplicity in mind, with features in the right places, not hundreds of tiny buttons, nested tabs or submenu; productivity comes first.
The main goal is to develop a **forever 100% free (without paid premium feature)**, full featured, as possible community driven, cross platform and open source alternative, empowered by JavaScript ecosystem.
A modern application created with minimalism and simplicity in mind, with features in the right places, not hundreds of tiny buttons, nested tabs or submenues; productivity comes first.
## Installation
Based on your operating system you can have one or more distribution formats to choose based on your preferences.
Since Antares SQL is a free software we haven't a budget to spend in annual licenses or certificates. This can result that on some platforms you need some additional passages to install this app.
Since Antares SQL is a free software we don't have a budget to spend on annual licenses or certificates. This can result that on some platforms you might need to put in some additional work to install this app.
### Linux
On Linux you can simply download and run `.AppImage` distributions, install from Snap Store or from AUR.
On Linux you can simply download and run the `.AppImage` distribution, install from Snap Store, from AUR or from our [PPA repository](https://github.com/antares-sql/antares-ppa).
### Windows
On Windows you can choose between Microsoft Store and download `.exe` distribution. The latter lacks of a certificate, so to install you need to click on "More info" and then "Run anyway" on SmartScreen prompt.
On Windows you can choose between downloading the app from Microsoft Store or downloading the `.exe` from our [website](https://antares-sql.app/downloads) or [this github repo](https://github.com/Fabio286/antares/releases/latest). Distributions that are not from Microsoft Store are not signed with a certificate, so to install you need to click on "More info" and then "Run anyway" on SmartScreen prompt.
### MacOS
@@ -61,7 +63,7 @@ On macOS you can run `.dmg` distribution following [this guide](https://support.
## Download
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/antares) [![Get it from AUR](https://raw.githubusercontent.com/Fabio286/antares/3e00c4bae6e036300c752c1a40c5a038fea9c169/docs/aur-badge.svg)](https://aur.archlinux.org/packages/antares-sql/) [![Get it from Microsoft Store](https://raw.githubusercontent.com/Fabio286/antares/gh-pages/src/assets/ms-store.png)](https://www.microsoft.com/p/antares-sql-client/9nhtb9sq51r1?cid=storebadge&ocid=badge&rtc=1&activetab=pivot:overviewtab)
[![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-black.svg)](https://snapcraft.io/antares) [![Get it from AUR](https://raw.githubusercontent.com/Fabio286/antares/3e00c4bae6e036300c752c1a40c5a038fea9c169/docs/aur-badge.svg)](https://aur.archlinux.org/packages/antares-sql/) [<img src="https://developer.microsoft.com/store/badges/images/English_get-it-from-MS.png" style="height: 56px">](https://www.microsoft.com/p/antares-sql-client/9nhtb9sq51r1?cid=storebadge&ocid=badge&rtc=1&activetab=pivot:overviewtab)
🚀 **[Other Downloads](https://github.com/Fabio286/antares/releases/latest)**
## Coming soon
@@ -72,7 +74,6 @@ This is a roadmap with major features will come in near future.
- Users management (add/edit/delete).
- More context menu shortcuts.
- More keyboard shortcuts.
- Import/export and migration.
- Support for other databases.
- Apple Silicon distribution
@@ -83,8 +84,8 @@ This is a roadmap with major features will come in near future.
- [x] MySQL/MariaDB
- [x] PostgreSQL
- [x] SQLite
- [ ] MSSQL
- [ ] OracleDB
- [x] Firebird SQL
- [ ] SQL Server
- [ ] More...
### Operating Systems
@@ -105,7 +106,7 @@ This is a roadmap with major features will come in near future.
- 🌍 [Translate Antares](https://github.com/Fabio286/antares/wiki/Translate-Antares)
- 📖 [Contributors Guide](https://github.com/Fabio286/antares/wiki/Contributors-Guide)
- 🚧 [Project Board](https://github.com/users/Fabio286/projects/1)
- 🚧 [Project Board](https://github.com/antares-sql/antares/projects/1)
## Contributors ✨
@@ -115,22 +116,35 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://fabiodistasio.it/"><img src="https://avatars.githubusercontent.com/u/31471771?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Fabio Di Stasio</b></sub></a><br /><a href="https://github.com/Fabio286/antares/commits?author=Fabio286" title="Code">💻</a> <a href="#translation-Fabio286" title="Translation">🌍</a> <a href="https://github.com/Fabio286/antares/commits?author=Fabio286" title="Documentation">📖</a></td>
<td align="center"><a href="https://www.linkedin.com/in/giulioganci/"><img src="https://avatars.githubusercontent.com/u/4192159?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Giulio Ganci</b></sub></a><br /><a href="https://github.com/Fabio286/antares/commits?author=toriphes" title="Code">💻</a></td>
<td align="center"><a href="https://christianratz.de/"><img src="https://avatars.githubusercontent.com/u/2630316?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Christian Ratz</b></sub></a><br /><a href="https://github.com/Fabio286/antares/commits?author=digitalgopnik" title="Code">💻</a> <a href="#translation-digitalgopnik" title="Translation">🌍</a></td>
<td align="center"><a href="https://reverb6821.github.io/"><img src="https://avatars.githubusercontent.com/u/55198803?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Giuseppe Gigliotti</b></sub></a><br /><a href="#translation-reverb6821" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/Mohd-PH"><img src="https://avatars.githubusercontent.com/u/9362157?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mohd-PH</b></sub></a><br /><a href="#translation-Mohd-PH" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/hongkfui"><img src="https://avatars.githubusercontent.com/u/37477191?v=4?s=100" width="100px;" alt=""/><br /><sub><b>hongkfui</b></sub></a><br /><a href="#translation-hongkfui" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/MrAnyx"><img src="https://avatars.githubusercontent.com/u/44176707?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Robin</b></sub></a><br /><a href="#translation-MrAnyx" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/daeleduardo"><img src="https://avatars.githubusercontent.com/u/8599078?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Daniel Eduardo</b></sub></a><br /><a href="#translation-daeleduardo" title="Translation">🌍</a></td>
<td align="center"><a href="https://ngoquocdat.com/"><img src="https://avatars.githubusercontent.com/u/56961917?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ngô Quốc Đạt</b></sub></a><br /><a href="#translation-datlechin" title="Translation">🌍</a></td>
<td align="center"><a href="https://github.com/IsamuSugi"><img src="https://avatars.githubusercontent.com/u/7746658?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Isamu Sugiura</b></sub></a><br /><a href="#translation-IsamuSugi" title="Translation">🌍</a></td>
<td align="center"><a href="http://rsacchetto.nexxontech.it/"><img src="https://avatars.githubusercontent.com/u/18429412?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Riccardo Sacchetto</b></sub></a><br /><a href="#platform-Occhioverde" title="Packaging/porting to new platform">📦</a></td>
<td align="center"><a href="https://kilianstallinger.com"><img src="https://avatars.githubusercontent.com/u/5290318?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Kilian Stallinger</b></sub></a><br /><a href="https://github.com/Fabio286/antares/commits?author=kilianstallz" title="Code">💻</a></td>
</tr>
<tbody>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://fabiodistasio.it/"><img src="https://avatars.githubusercontent.com/u/31471771?v=4?s=100" width="100px;" alt="Fabio Di Stasio"/><br /><sub><b>Fabio Di Stasio</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=Fabio286" title="Code">💻</a> <a href="#translation-Fabio286" title="Translation">🌍</a> <a href="https://github.com/antares-sql/antares/commits?author=Fabio286" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://www.linkedin.com/in/giulioganci/"><img src="https://avatars.githubusercontent.com/u/4192159?v=4?s=100" width="100px;" alt="Giulio Ganci"/><br /><sub><b>Giulio Ganci</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=toriphes" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://christianratz.de/"><img src="https://avatars.githubusercontent.com/u/2630316?v=4?s=100" width="100px;" alt="Christian Ratz"/><br /><sub><b>Christian Ratz</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=digitalgopnik" title="Code">💻</a> <a href="#translation-digitalgopnik" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://reverb6821.github.io/"><img src="https://avatars.githubusercontent.com/u/55198803?v=4?s=100" width="100px;" alt="Giuseppe Gigliotti"/><br /><sub><b>Giuseppe Gigliotti</b></sub></a><br /><a href="#translation-reverb6821" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/Mohd-PH"><img src="https://avatars.githubusercontent.com/u/9362157?v=4?s=100" width="100px;" alt="Mohd-PH"/><br /><sub><b>Mohd-PH</b></sub></a><br /><a href="#translation-Mohd-PH" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/hongkfui"><img src="https://avatars.githubusercontent.com/u/37477191?v=4?s=100" width="100px;" alt="hongkfui"/><br /><sub><b>hongkfui</b></sub></a><br /><a href="#translation-hongkfui" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/MrAnyx"><img src="https://avatars.githubusercontent.com/u/44176707?v=4?s=100" width="100px;" alt="Robin"/><br /><sub><b>Robin</b></sub></a><br /><a href="#translation-MrAnyx" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/daeleduardo"><img src="https://avatars.githubusercontent.com/u/8599078?v=4?s=100" width="100px;" alt="Daniel Eduardo"/><br /><sub><b>Daniel Eduardo</b></sub></a><br /><a href="#translation-daeleduardo" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://ngoquocdat.com/"><img src="https://avatars.githubusercontent.com/u/56961917?v=4?s=100" width="100px;" alt="Ngô Quốc Đạt"/><br /><sub><b>Ngô Quốc Đạt</b></sub></a><br /><a href="#translation-datlechin" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/IsamuSugi"><img src="https://avatars.githubusercontent.com/u/7746658?v=4?s=100" width="100px;" alt="Isamu Sugiura"/><br /><sub><b>Isamu Sugiura</b></sub></a><br /><a href="#translation-IsamuSugi" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://rsacchetto.nexxontech.it/"><img src="https://avatars.githubusercontent.com/u/18429412?v=4?s=100" width="100px;" alt="Riccardo Sacchetto"/><br /><sub><b>Riccardo Sacchetto</b></sub></a><br /><a href="#platform-Occhioverde" title="Packaging/porting to new platform">📦</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://kilianstallinger.com"><img src="https://avatars.githubusercontent.com/u/5290318?v=4?s=100" width="100px;" alt="Kilian Stallinger"/><br /><sub><b>Kilian Stallinger</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=kilianstallz" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/wenj91"><img src="https://avatars.githubusercontent.com/u/12549338?v=4?s=100" width="100px;" alt="文杰"/><br /><sub><b>文杰</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=wenj91" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/goYou"><img src="https://avatars.githubusercontent.com/u/62732795?v=4?s=100" width="100px;" alt="goYou"/><br /><sub><b>goYou</b></sub></a><br /><a href="#translation-goYou" title="Translation">🌍</a></td>
</tr>
<tr>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/raliqala"><img src="https://avatars.githubusercontent.com/u/30502407?v=4?s=100" width="100px;" alt="Topollo"/><br /><sub><b>Topollo</b></sub></a><br /><a href="https://github.com/antares-sql/antares/commits?author=raliqala" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/SmileYzn"><img src="https://avatars.githubusercontent.com/u/5851851?v=4?s=100" width="100px;" alt="Cleverson"/><br /><sub><b>Cleverson</b></sub></a><br /><a href="#translation-SmileYzn" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/fredatgithub"><img src="https://avatars.githubusercontent.com/u/6720055?v=4?s=100" width="100px;" alt="fred"/><br /><sub><b>fred</b></sub></a><br /><a href="#translation-fredatgithub" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/xak666"><img src="https://avatars.githubusercontent.com/u/38811437?v=4?s=100" width="100px;" alt="xaka_xak"/><br /><sub><b>xaka_xak</b></sub></a><br /><a href="#translation-xak666" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://codepen.io/theo-billardey"><img src="https://avatars.githubusercontent.com/u/48206778?v=4?s=100" width="100px;" alt="Théo Billardey"/><br /><sub><b>Théo Billardey</b></sub></a><br /><a href="#translation-brdtheo" title="Translation">🌍</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://yaskur.net"><img src="https://avatars.githubusercontent.com/u/9539970?v=4?s=100" width="100px;" alt="Muhammad Dyas Yaskur"/><br /><sub><b>Muhammad Dyas Yaskur</b></sub></a><br /><a href="#translation-dyaskur" title="Translation">🌍</a> <a href="https://github.com/antares-sql/antares/commits?author=dyaskur" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jimcat8"><img src="https://avatars.githubusercontent.com/u/86754294?v=4?s=100" width="100px;" alt="tianci li"/><br /><sub><b>tianci li</b></sub></a><br /><a href="#translation-jimcat8" title="Translation">🌍</a></td>
</tr>
</tbody>
</table>
<!-- markdownlint-restore -->

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

BIN
assets/linux/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
assets/linux/16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

BIN
assets/linux/256x256.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
assets/linux/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
assets/linux/64x64.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

0
misc/.gitkeep Normal file
View File

23642
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,31 +1,36 @@
{
"name": "antares",
"productName": "Antares",
"version": "0.4.1",
"version": "0.7.5",
"description": "A modern, fast and productivity driven SQL client with a focus in UX.",
"license": "MIT",
"repository": "https://github.com/Fabio286/antares.git",
"repository": "https://github.com/antares-sql/antares.git",
"scripts": {
"debug": "npm run rebuild:electron && npm run debug-runner",
"debug-runner": "node scripts/devRunner.js --remote-debug",
"compile": "npm run compile:main && npm run compile:renderer",
"compile": "npm run compile:main && npm run compile:workers && npm run compile:renderer",
"compile:main": "webpack --mode=production --config webpack.main.config.js",
"compile:workers": "webpack --mode=production --config webpack.workers.config.js",
"compile:renderer": "webpack --mode=production --config webpack.renderer.config.js",
"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",
"build": "cross-env NODE_ENV=production npm run compile && electron-builder --publish never",
"build:appx": "npm run build -- --win appx",
"rebuild:electron": "rimraf ./dist && npm run postinstall && npm run devtools:install",
"release": "standard-version",
"release:pre": "npm run release -- --prerelease alpha",
"devtools:install": "node scripts/devtoolsInstaller",
"postinstall": "electron-builder install-app-deps",
"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",
"test:e2e": "npm run compile && npm run test:e2e-dry",
"test:e2e-dry": "xvfb-maybe -- playwright test",
"lint": "eslint . --ext .js,.ts,.vue && stylelint \"./src/**/*.{css,scss,sass,vue}\"",
"lint:fix": "eslint . --ext .js,.ts,.vue --fix && stylelint \"./src/**/*.{css,scss,sass,vue}\" --fix",
"contributors:add": "all-contributors add",
"contributors:generate": "all-contributors generate"
},
"author": "Fabio Di Stasio <fabio286@gmail.com>",
"main": "./dist/main.js",
"antares": {
"devtoolsId": "nhdogjmejiglipccpnnnanhbledajbpd"
},
"build": {
"appId": "com.fabio286.antares",
"artifactName": "${productName}-${version}-${os}_${arch}.${ext}",
@@ -59,7 +64,11 @@
"target": [
{
"target": "deb",
"arch": "x64"
"arch": [
"x64",
"armv7l",
"arm64"
]
},
{
"target": "AppImage",
@@ -70,12 +79,19 @@
]
}
],
"icon": "assets/linux",
"category": "Development"
},
"appImage": {
"license": "./LICENSE",
"category": "Development"
},
"nsis": {
"license": "./LICENSE",
"installerIcon": "assets/icon.ico",
"uninstallerIcon": "assets/icon.ico",
"installerHeader": "assets/icon.ico"
},
"portable": {
"artifactName": "${productName}-${version}-portable.exe"
},
@@ -103,66 +119,96 @@
}
},
"dependencies": {
"@electron/remote": "^2.0.1",
"@mdi/font": "^6.1.95",
"@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",
"faker": "^5.5.3",
"marked": "^4.0.0",
"moment": "^2.29.1",
"mysql2": "^2.3.2",
"pg": "^8.7.1",
"pgsql-ast-parser": "^7.2.1",
"source-map-support": "^0.5.20",
"spectre.css": "^0.5.9",
"sql-formatter": "^4.0.2",
"ssh2-promise": "^1.0.2",
"v-mask": "^2.3.0",
"vue-i18n": "^8.26.5",
"vuedraggable": "^2.24.3",
"vuex": "^3.6.2"
"@electron/remote": "~2.0.1",
"@faker-js/faker": "~6.1.2",
"@mdi/font": "~7.1.96",
"@turf/helpers": "~6.5.0",
"@vueuse/core": "~8.7.5",
"ace-builds": "~1.14.0",
"better-sqlite3": "~8.0.0",
"electron-log": "~4.4.1",
"electron-store": "~8.1.0",
"electron-updater": "~4.6.5",
"electron-window-state": "~5.0.3",
"encoding": "~0.1.13",
"floating-vue": "~2.0.0-beta.20",
"leaflet": "~1.7.1",
"marked": "~4.0.19",
"moment": "~2.29.4",
"mysql2": "~2.3.2",
"node-firebird": "~1.1.4",
"pg": "~8.7.1",
"pg-connection-string": "~2.5.0",
"pg-query-stream": "~4.2.3",
"pgsql-ast-parser": "~7.2.1",
"pinia": "~2.0.28",
"source-map-support": "~0.5.20",
"spectre.css": "~0.5.9",
"sql-formatter": "~12.0.3",
"ssh2-promise": "~1.0.2",
"v-mask": "~2.3.0",
"vue": "~3.2.45",
"vue-i18n": "~9.2.2",
"vuedraggable": "~4.1.0"
},
"devDependencies": {
"@babel/eslint-parser": "^7.15.7",
"@babel/preset-env": "^7.15.8",
"all-contributors-cli": "^6.20.0",
"babel-loader": "^8.2.3",
"chalk": "^4.1.2",
"clean-webpack-plugin": "^4.0.0",
"cross-env": "^7.0.2",
"css-loader": "^6.5.0",
"electron": "^16.0.1",
"electron-builder": "^22.14.10",
"electron-devtools-installer": "^3.2.0",
"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": "^8.0.3",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^5.5.0",
"mini-css-extract-plugin": "^2.4.3",
"node-loader": "^2.0.0",
"playwright": "^1.16.3",
"progress-webpack-plugin": "^1.0.12",
"sass": "^1.42.1",
"sass-loader": "^12.3.0",
"standard-version": "^9.3.1",
"style-loader": "^3.3.1",
"stylelint": "^13.13.1",
"stylelint-config-standard": "^22.0.0",
"stylelint-scss": "^3.21.0",
"tree-kill": "^1.2.2",
"vue": "^2.6.14",
"vue-loader": "^15.9.8",
"vue-template-compiler": "^2.6.14",
"webpack": "^5.60.0",
"webpack-cli": "^4.9.1",
"webpack-dev-server": "^4.4.0"
"@babel/eslint-parser": "~7.15.7",
"@babel/preset-env": "~7.15.8",
"@babel/preset-typescript": "~7.16.7",
"@playwright/test": "~1.28.1",
"@types/better-sqlite3": "~7.5.0",
"@types/leaflet": "~1.7.9",
"@types/marked": "~4.0.7",
"@types/node": "~17.0.23",
"@types/pg": "~8.6.5",
"@types/ssh2": "~1.11.6",
"@typescript-eslint/eslint-plugin": "~5.18.0",
"@typescript-eslint/parser": "~5.18.0",
"@vue/compiler-sfc": "~3.2.33",
"all-contributors-cli": "~6.20.0",
"babel-loader": "~8.2.3",
"chalk": "~4.1.2",
"cross-env": "~7.0.2",
"css-loader": "~6.5.0",
"electron": "~22.0.3",
"electron-builder": "~22.10.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.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.5",
"node-loader": "~2.0.0",
"playwright": "~1.28.1",
"playwright-core": "~1.28.1",
"postcss-html": "~1.5.0",
"progress-webpack-plugin": "~1.0.12",
"rimraf": "~3.0.2",
"sass": "~1.42.1",
"sass-loader": "~12.3.0",
"standard-version": "~9.3.1",
"style-loader": "~3.3.1",
"stylelint": "~14.9.1",
"stylelint-config-recommended-vue": "~1.4.0",
"stylelint-config-standard": "~26.0.0",
"stylelint-scss": "~4.3.0",
"tree-kill": "~1.2.2",
"ts-loader": "~9.2.8",
"typescript": "~4.6.3",
"unzip-crx-3": "~0.2.0",
"vue-eslint-parser": "~8.3.0",
"vue-loader": "~16.8.3",
"webpack": "~5.72.0",
"webpack-cli": "~4.9.1",
"webpack-dev-server": "~4.11.1",
"xvfb-maybe": "~0.2.1"
},
"overrides": {
"ssh2-promise": {
"ssh2": "github:Fabio286/ssh2"
}
}
}

View File

@@ -1,5 +1,6 @@
process.env.NODE_ENV = 'development';
// process.env.ELECTRON_ENABLE_LOGGING = true
process.env.ELECTRON_DISABLE_SECURITY_WARNINGS = false;
const chalk = require('chalk');
const electron = require('electron');
@@ -12,14 +13,14 @@ const { spawn } = require('child_process');
const mainConfig = require('../webpack.main.config');
const rendererConfig = require('../webpack.renderer.config');
// const workersConfig = require('../webpack.workers.config');
const workersConfig = require('../webpack.workers.config');
let electronProcess = null;
let manualRestart = null;
const remoteDebugging = process.argv.includes('--remote-debug');
if (remoteDebugging) {
// disable dvtools open in electron
// disable devtools open in electron
process.env.RENDERER_REMOTE_DEBUGGING = true;
}
@@ -58,13 +59,13 @@ async function restartElectron () {
console.error(chalk.red(data.toString()));
});
electronProcess.on('exit', (code, signal) => {
electronProcess.on('exit', () => {
if (!manualRestart) process.exit(0);
});
}
function startMain () {
const webpackSetup = webpack(mainConfig);
const webpackSetup = webpack([mainConfig, workersConfig]);
webpackSetup.compilers.forEach((compiler) => {
const { name } = compiler;
@@ -113,7 +114,6 @@ function startRenderer (callback) {
});
const server = new WebpackDevServer(compiler, {
hot: true,
port: 9080,
client: {
overlay: true,

View File

@@ -0,0 +1,49 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck
const fs = require('fs');
const path = require('path');
const https = require('https');
const unzip = require('unzip-crx-3');
const { antares } = require('../package.json');
const extensionID = antares.devtoolsId;
const destFolder = path.resolve(__dirname, `../misc/${extensionID}`);
const filePath = path.resolve(__dirname, `${destFolder}${extensionID}.crx`);
const fileUrl = `https://clients2.google.com/service/update2/crx?response=redirect&acceptformat=crx2,crx3&x=id%3D${extensionID}%26uc&prodversion=32`;
const fileStream = fs.createWriteStream(filePath);
const downloadFile = url => {
return new Promise((resolve, reject) => {
const request = https.get(url);
request.on('response', response => {
if (response.statusCode && response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
return downloadFile(response.headers.location)
.then(resolve)
.catch(reject);
}
response.pipe(fileStream);
response.on('close', () => {
console.log('Devtools download completed!');
resolve();
});
response.on('error', reject);
});
request.on('error', reject);
request.end();
});
};
(async () => {
try {
await downloadFile(fileUrl);
await unzip(filePath, destFolder);
fs.unlinkSync(filePath);
fs.unlinkSync(`${destFolder}/package.json`);// <- Avoid to display annoyng npm script in vscode
}
catch (error) {
console.log(error);
}
})();

View File

@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export default class {
static get _methods () {
return [
@@ -139,7 +140,7 @@ export default class {
{ name: 'arrayElement', group: 'random', types: ['string'] },
{ name: 'arrayElements', group: 'random', types: ['string'] },
{ name: 'objectElement', group: 'random', types: ['string'] },
{ name: 'uuid', group: 'random', types: ['string'] },
{ name: 'uuid', group: 'random', types: ['string', 'uuid'] },
{ name: 'boolean', group: 'random', types: ['string'] },
{ name: 'word', group: 'random', types: ['string'] },
{ name: 'words', group: 'random', types: ['string'] },
@@ -180,7 +181,7 @@ export default class {
acc[curr.group] = new Set(curr.types);
return acc;
}, {});
}, {} as any);
const groupsArr = [];
@@ -195,15 +196,15 @@ export default class {
return 1;
return 0;
}); ;
});
}
static getGroupsByType (type) {
static getGroupsByType (type: string) {
if (!type) return [];
return this.getGroups().filter(group => group.types.includes(type));
}
static getMethods ({ type, group }) {
static getMethods ({ type, group }: {type: string; group: string}) {
return this._methods.filter(method => method.group === group && method.types.includes(type)).sort((a, b) => {
if (a.name < b.name)
return -1;

View File

@@ -1,8 +1,14 @@
module.exports = {
import { Customizations } from '../interfaces/customizations';
// Everything OFF
export const defaults: Customizations = {
// Defaults
defaultPort: null,
defaultUser: null,
defaultDatabase: null,
dataTypes: [],
indexTypes: [],
foreignActions: [],
// Core
database: false,
collations: false,
@@ -11,6 +17,7 @@ module.exports = {
sslConnection: false,
sshConnection: false,
fileConnection: false,
cancelQueries: false,
// Tools
processesList: false,
usersManagement: false,
@@ -28,6 +35,7 @@ module.exports = {
elementsWrapper: '',
stringsWrapper: '"',
tableAdd: false,
tableTruncateDisableFKCheck: false,
viewAdd: false,
triggerAdd: false,
triggerFunctionAdd: false,
@@ -37,10 +45,13 @@ module.exports = {
databaseEdit: false,
schemaEdit: false,
schemaDrop: false,
schemaExport: false,
exportByChunks: false,
schemaImport: false,
tableSettings: false,
tableOptions: false,
tableArray: false,
tableRealCount: false,
tableDuplicate: false,
viewSettings: false,
triggerSettings: false,
triggerFunctionSettings: false,
@@ -64,24 +75,25 @@ module.exports = {
viewUpdateOption: false,
procedureDeterministic: false,
procedureDataAccess: false,
procedureSql: false,
procedureSql: null,
procedureContext: false,
procedureContextValues: [],
procedureLanguage: false,
functionDeterministic: false,
functionDataAccess: false,
functionSql: false,
functionSql: null,
functionContext: false,
functionLanguage: false,
triggerSql: false,
triggerSql: null,
triggerStatementInCreation: false,
triggerMultipleEvents: false,
triggerTableInName: false,
triggerUpdateColumns: false,
triggerOnlyRename: false,
triggerEnableDisable: false,
triggerFunctionSql: false,
triggerFunctionlanguages: false,
triggerFunctionSql: null,
triggerFunctionlanguages: null,
parametersLength: false,
languages: false,
languages: null,
readOnlyMode: false
};

View File

@@ -0,0 +1,63 @@
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
import firebirdTypes from '../data-types/firebird';
export const customizations: Customizations = {
...defaults,
// Defaults
defaultPort: 3050,
defaultUser: 'SYSDBA',
defaultDatabase: null,
dataTypes: firebirdTypes,
indexTypes: [
'PRIMARY',
// 'CHECK',
'UNIQUE'
],
foreignActions: [
'RESTRICT',
'NO ACTION',
'CASCADE',
'SET NULL',
'SET DEFAULT'
],
// Core
database: true,
collations: false,
engines: false,
connectionSchema: false,
sslConnection: false,
sshConnection: false,
fileConnection: false,
cancelQueries: false,
// Tools
processesList: false,
usersManagement: false,
variables: false,
// Structure
schemas: false,
tables: true,
views: true,
triggers: true,
routines: true,
functions: false,
// Settings
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableSettings: true,
tableRealCount: true,
viewAdd: true,
viewSettings: true,
triggerAdd: true,
triggerMultipleEvents: true,
triggerSql: 'BEGIN\r\n\r\nEND',
routineAdd: true,
procedureContext: true,
procedureContextValues: ['IN', 'OUT'],
procedureSql: 'BEGIN\r\n\r\nEND',
parametersLength: true,
indexes: true,
foreigns: true,
nullable: true
};

View File

@@ -1,6 +0,0 @@
module.exports = {
maria: require('./mysql'),
mysql: require('./mysql'),
pg: require('./postgresql'),
sqlite: require('./sqlite')
};

View File

@@ -0,0 +1,19 @@
import * as mysql from 'common/customizations/mysql';
import * as postgresql from 'common/customizations/postgresql';
import * as sqlite from 'common/customizations/sqlite';
import * as firebird from 'common/customizations/firebird';
import { Customizations } from 'common/interfaces/customizations';
export default {
maria: mysql.customizations,
mysql: mysql.customizations,
pg: postgresql.customizations,
sqlite: sqlite.customizations,
firebird: firebird.customizations
} as {
maria: Customizations;
mysql: Customizations;
pg: Customizations;
sqlite: Customizations;
firebird: Customizations;
};

View File

@@ -1,17 +1,33 @@
const defaults = require('./defaults');
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
import mysqlTypes from '../data-types/mysql';
module.exports = {
export const customizations: Customizations = {
...defaults,
// Defaults
defaultPort: 3306,
defaultUser: 'root',
defaultDatabase: null,
dataTypes: mysqlTypes,
indexTypes: [
'PRIMARY',
'INDEX',
'UNIQUE',
'FULLTEXT'
],
foreignActions: [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
],
// Core
connectionSchema: true,
collations: true,
engines: true,
sslConnection: true,
sshConnection: true,
cancelQueries: true,
// Tools
processesList: true,
// Structure
@@ -23,9 +39,11 @@ module.exports = {
functions: true,
schedulers: true,
// Settings
elementsWrapper: '',
elementsWrapper: '`',
stringsWrapper: '"',
tableAdd: true,
tableTruncateDisableFKCheck: true,
tableDuplicate: true,
viewAdd: true,
triggerAdd: true,
routineAdd: true,
@@ -33,6 +51,9 @@ module.exports = {
schedulerAdd: true,
schemaEdit: true,
schemaDrop: true,
schemaExport: true,
exportByChunks: true,
schemaImport: true,
tableSettings: true,
viewSettings: true,
triggerSettings: true,
@@ -45,7 +66,6 @@ module.exports = {
unsigned: true,
nullable: true,
zerofill: true,
tableOptions: true,
autoIncrement: true,
comment: true,
collation: true,
@@ -58,6 +78,7 @@ module.exports = {
procedureDataAccess: true,
procedureSql: 'BEGIN\r\n\r\nEND',
procedureContext: true,
procedureContextValues: ['IN', 'OUT', 'INOUT'],
triggerSql: 'BEGIN\r\n\r\nEND',
functionDeterministic: true,
functionDataAccess: true,

View File

@@ -1,15 +1,30 @@
const defaults = require('./defaults');
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
import postgresqlTypes from '../data-types/postgresql';
module.exports = {
export const customizations: Customizations = {
...defaults,
// Defaults
defaultPort: 5432,
defaultUser: 'postgres',
defaultDatabase: 'postgres',
dataTypes: postgresqlTypes,
indexTypes: [
'PRIMARY',
'INDEX',
'UNIQUE'
],
foreignActions: [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
],
// Core
database: true,
sslConnection: true,
sshConnection: true,
cancelQueries: true,
// Tools
processesList: true,
// Structure
@@ -24,12 +39,15 @@ module.exports = {
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableDuplicate: true,
viewAdd: true,
triggerAdd: true,
triggerFunctionAdd: true,
routineAdd: true,
functionAdd: true,
schemaDrop: true,
schemaExport: true,
schemaImport: true,
databaseEdit: false,
tableSettings: true,
viewSettings: true,
@@ -43,6 +61,7 @@ module.exports = {
tableArray: true,
procedureSql: '$procedure$\r\n\r\n$procedure$',
procedureContext: true,
procedureContextValues: ['IN', 'OUT', 'INOUT'],
procedureLanguage: true,
functionSql: '$function$\r\n\r\n$function$',
triggerFunctionSql: '$function$\r\nBEGIN\r\n\r\nEND\r\n$function$',

View File

@@ -1,4 +1,21 @@
module.exports = {
import { Customizations } from '../interfaces/customizations';
import { defaults } from './defaults';
import sqliteTypes from '../data-types/sqlite';
export const customizations: Customizations = {
...defaults,
dataTypes: sqliteTypes,
indexTypes: [
'PRIMARY',
'INDEX',
'UNIQUE'
],
foreignActions: [
'RESTRICT',
'CASCADE',
'SET NULL',
'NO ACTION'
],
// Core
fileConnection: true,
// Structure
@@ -10,6 +27,7 @@ module.exports = {
elementsWrapper: '"',
stringsWrapper: '\'',
tableAdd: true,
tableDuplicate: true,
viewAdd: true,
triggerAdd: true,
schemaEdit: false,

View File

@@ -0,0 +1,136 @@
import { TypesGroup } from 'common/interfaces/antares';
export default [
{
group: 'integer',
types: [
{
name: 'SMALLINT',
length: false,
collation: false,
unsigned: true,
zerofill: true
},
{
name: 'INTEGER',
length: false,
collation: false,
unsigned: true,
zerofill: true
},
{
name: 'BIGINT',
length: false,
collation: false,
unsigned: true,
zerofill: true
}
]
},
{
group: 'float',
types: [
{
name: 'DECIMAL',
length: true,
scale: true,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'NUMERIC',
length: true,
scale: true,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'FLOAT',
length: false,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'DOUBLE PRECISION',
length: false,
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: 'BLOB-TEXT',
length: false,
collation: true,
unsigned: false,
zerofill: false
}
]
},
{
group: 'binary',
types: [
{
name: 'BLOB',
length: false,
collation: false,
unsigned: false,
zerofill: false
},
{
name: 'CHAR-BINARY',
length: false,
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: 'TIMESTAMP',
length: false,
collation: false,
unsigned: false,
zerofill: false
}
]
}
] as TypesGroup[];

View File

@@ -1,4 +1,6 @@
module.exports = [
import { TypesGroup } from 'common/interfaces/antares';
export default [
{
group: 'integer',
types: [
@@ -58,7 +60,7 @@ module.exports = [
},
{
name: 'DOUBLE',
length: true,
length: false,
collation: false,
unsigned: false,
zerofill: false
@@ -66,6 +68,7 @@ module.exports = [
{
name: 'DECIMAL',
length: true,
scale: true,
collation: false,
unsigned: false,
zerofill: false
@@ -120,7 +123,7 @@ module.exports = [
{
name: 'JSON',
length: false,
collation: true,
collation: false,
unsigned: false,
zerofill: false
}
@@ -218,56 +221,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
@@ -305,4 +308,4 @@ module.exports = [
}
]
}
];
] as TypesGroup[];

View File

@@ -1,4 +1,6 @@
module.exports = [
import { TypesGroup } from 'common/interfaces/antares';
export default [
{
group: 'integer',
types: [
@@ -22,11 +24,6 @@ module.exports = [
length: false,
unsigned: true
},
{
name: 'NUMERIC',
length: true,
unsigned: true
},
{
name: 'SMALLSERIAL',
length: false,
@@ -52,6 +49,12 @@ module.exports = [
length: false,
unsigned: true
},
{
name: 'NUMERIC',
length: true,
unsigned: true,
scale: true
},
{
name: 'DOUBLE PRECISION',
length: false,
@@ -289,4 +292,4 @@ module.exports = [
}
]
}
];
] as TypesGroup[];

View File

@@ -1,10 +1,12 @@
module.exports = [
import { TypesGroup } from 'common/interfaces/antares';
export default [
{
group: 'integer',
types: [
{
name: 'INT',
length: true,
length: 10,
collation: false,
unsigned: true,
zerofill: true
@@ -16,6 +18,13 @@ module.exports = [
unsigned: true,
zerofill: true
},
{
name: 'INTEGER UNSIGNED',
length: true,
collation: false,
unsigned: true,
zerofill: true
},
{
name: 'BIGINT',
length: true,
@@ -134,4 +143,4 @@ module.exports = [
}
]
}
];
] as TypesGroup[];

View File

@@ -8,7 +8,10 @@ export const TEXT = [
export const LONG_TEXT = [
'TEXT',
'MEDIUMTEXT',
'LONGTEXT'
'LONGTEXT',
'JSON',
'VARBINARY',
'BLOB-TEXT'
];
export const ARRAY = [
@@ -27,24 +30,31 @@ export const NUMBER = [
'SMALLINT',
'MEDIUMINT',
'BIGINT',
'DECIMAL',
'NUMERIC',
'INTEGER',
'SMALLSERIAL',
'SERIAL',
'BIGSERIAL',
'OID',
'XID'
'XID',
'INT64'
];
export const FLOAT = [
'FLOAT',
'DECIMAL',
'DOUBLE',
'REAL',
'DOUBLE PRECISION',
'MONEY'
];
export const IS_BIGINT = [
'BIGINT',
'BIGSERIAL',
'DOUBLE PRECISION'
];
export const BOOLEAN = [
'BOOL',
'BOOLEAN'
@@ -75,10 +85,41 @@ export const BLOB = [
'TINYBLOB',
'MEDIUMBLOB',
'LONGBLOB',
'BYTEA'
'LONG_BLOB',
'BYTEA',
'CHAR-BINARY'
];
export const BIT = [
'BIT',
'BIT VARYING'
];
export const BINARY = [
'BINARY'
];
export const UUID = [
'UUID'
];
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'
];

View File

@@ -1,6 +0,0 @@
module.exports = [
'PRIMARY',
'INDEX',
'UNIQUE',
'FULLTEXT'
];

View File

@@ -1,5 +0,0 @@
module.exports = [
'PRIMARY',
'INDEX',
'UNIQUE'
];

View File

@@ -1,5 +0,0 @@
module.exports = [
'PRIMARY',
'INDEX',
'UNIQUE'
];

View File

@@ -0,0 +1,405 @@
import * as mysql from 'mysql2/promise';
import * as pg from 'pg';
import MysqlExporter from 'src/main/libs/exporters/sql/MysqlExporter';
import PostgreSQLExporter from 'src/main/libs/exporters/sql/PostgreSQLExporter';
import MySQLImporter from 'src/main/libs/importers/sql/MySQLlImporter';
import PostgreSQLImporter from 'src/main/libs/importers/sql/PostgreSQLImporter';
import SSHConfig from 'ssh2-promise/lib/sshConfig';
import { MySQLClient } from '../../main/libs/clients/MySQLClient';
import { PostgreSQLClient } from '../../main/libs/clients/PostgreSQLClient';
import { SQLiteClient } from '../../main/libs/clients/SQLiteClient';
import { FirebirdSQLClient } from 'src/main/libs/clients/FirebirdSQLClient';
export type Client = MySQLClient | PostgreSQLClient | SQLiteClient | FirebirdSQLClient
export type ClientCode = 'mysql' | 'maria' | 'pg' | 'sqlite' | 'firebird'
export type Exporter = MysqlExporter | PostgreSQLExporter
export type Importer = MySQLImporter | PostgreSQLImporter
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface IpcResponse<T = any> {
status: 'success' | 'error';
response?: T;
}
/**
* Pasameters needed to create a new Antares connection to a database
*/
export interface ClientParams {
client: ClientCode;
uid?: string;
params:
mysql.ConnectionOptions & {schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean}
| pg.ClientConfig & {schema: string; ssl?: mysql.SslOptions; ssh?: SSHConfig; readonly: boolean}
| { databasePath: string; readonly: boolean };
poolSize?: number;
logger?: () => void;
}
/**
* Paramenets insered by user in connection mask
*/
export interface ConnectionParams {
uid: string;
name?: string;
client: ClientCode;
host: string;
database?: string;
schema?: string;
databasePath?: string;
port: number;
user: string;
password: string;
ask: boolean;
readonly: boolean;
ssl: boolean;
cert?: string;
key?: string;
ca?: string;
untrustedConnection: boolean;
ciphers?: string;
ssh: boolean;
sshHost?: string;
sshUser?: string;
sshPass?: string;
sshKey?: string;
sshPort?: number;
sshPassphrase?: string;
}
export interface TypeInformations {
name: string;
length: boolean;
scale: boolean;
collation: boolean;
unsigned: boolean;
zerofill: boolean;
}
export interface TypesGroup {
group: string;
types: TypeInformations[];
}
// Tables
export interface TableInfos {
name: string;
type: string;
rows: number;
engine: string;
comment: string;
size: number | false;
collation: string;
autoIncrement?: boolean;
}
export type TableOptions = Partial<TableInfos>;
export interface TableField {
// eslint-disable-next-line camelcase
_antares_id?: string;
name: string;
type: string;
schema: string;
table?: string;
numPrecision?: number;
numLength?: number;
datePrecision?: number;
charLength?: number;
numScale?: number;
nullable?: boolean;
unsigned?: boolean;
zerofill?: boolean;
order?: number;
default?: string;
defaultType?: string;
enumValues?: string;
charset?: string;
collation?: string;
autoIncrement?: boolean;
isArray?: boolean;
onUpdate?: string;
comment?: string;
after?: string;
orgName?: string;
length?: number | false;
alias: string;
tableAlias: string;
orgTable: string;
key?: 'pri' | 'uni' | '';
}
export interface TableIndex {
// eslint-disable-next-line camelcase
_antares_id?: string;
name: string;
fields: string[];
type: string;
comment?: string;
indexType?: string;
indexComment?: string;
cardinality?: number;
oldType?: string;
oldName?: string;
}
export interface TableForeign {
// eslint-disable-next-line camelcase
_antares_id?: string;
constraintName: string;
refSchema: string;
table: string;
refTable: string;
field: string;
refField: string;
onUpdate: string;
onDelete: string;
oldName?: string;
}
export interface CreateTableParams {
/** Connection UID */
uid?: string;
schema: string;
fields: TableField[];
foreigns: TableForeign[];
indexes: TableIndex[];
options: TableOptions;
}
export interface AlterTableParams {
/** Connection UID */
uid?: string;
schema: string;
table: string;
additions: TableField[];
changes: TableField[];
deletions: TableField[];
tableStructure: {
name: string;
fields: TableField[];
foreigns: TableForeign[];
indexes: TableIndex[];
};
indexChanges: {
additions: TableIndex[];
changes: TableIndex[];
deletions: TableIndex[];
};
foreignChanges: {
additions: TableForeign[];
changes: TableForeign[];
deletions: TableForeign[];
};
options: TableOptions;
}
// Views
export type ViewInfos = TableInfos
export interface CreateViewParams {
schema: string;
name: string;
algorithm: string;
definer: string;
security: string;
sql: string;
updateOption: string;
}
export interface AlterViewParams extends CreateViewParams {
oldName?: string;
}
// Triggers
export interface TriggerInfos {
name: string;
statement: string;
timing: string;
definer: string;
event: string;
table: string;
sqlMode: string;
created: Date;
charset: string;
enabled?: boolean;
}
export interface CreateTriggerParams {
definer?: string;
schema: string;
name: string;
activation: string;
event: string;
table: string;
sql: string;
}
export interface AlterTriggerParams extends CreateTriggerParams {
oldName?: string;
}
// Routines & Functions
export interface FunctionParam {
// eslint-disable-next-line camelcase
_antares_id: string;
context: string;
name: string;
type: string;
length: number;
}
export interface RoutineInfos {
name: string;
type?: string;
definer: string;
created?: string;
sql?: string;
updated?: string;
comment?: string;
charset?: string;
security?: string;
language?: string;
dataAccess?: string;
deterministic?: boolean;
parameters?: FunctionParam[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
returns?: any;
returnsLength?: number;
}
export type FunctionInfos = RoutineInfos
export type TriggerFunctionInfos = FunctionInfos
export interface CreateRoutineParams {
name: string;
parameters?: FunctionParam[];
definer: string;
schema: string;
deterministic: boolean;
dataAccess: string;
security: string;
comment?: string;
language?: string;
sql: string;
}
export interface AlterRoutineParams extends CreateRoutineParams {
oldName?: string;
}
export interface CreateFunctionParams {
name: string;
parameters?: FunctionParam[];
definer: string;
schema: string;
deterministic: boolean;
dataAccess: string;
security: string;
comment?: string;
sql: string;
returns: string;
returnsLength: number;
language?: string;
}
export interface AlterFunctionParams extends CreateFunctionParams {
oldName?: string;
}
// Events
export interface EventInfos {
definer?: string;
schema: string;
name: string;
execution: string;
every: string[];
starts: string;
ends: string;
at: string;
preserve: boolean;
state: string;
comment: string;
enabled?: boolean;
sql: string;
}
export type CreateEventParams = EventInfos;
export interface AlterEventParams extends CreateEventParams {
oldName?: string;
}
// Schema
export interface SchemaInfos {
name: string;
size: number;
tables: TableInfos[];
functions: FunctionInfos[];
procedures: RoutineInfos[];
triggers: TriggerInfos[];
schedulers: EventInfos[];
}
export interface CollationInfos {
charset: string;
collation: string;
compiled: boolean;
default: boolean;
id: string | number;
sortLen: number;
}
// Query
export interface QueryBuilderObject {
schema: string;
select: string[];
from: string;
where: string[];
groupBy: string[];
orderBy: string[];
limit: number;
offset: number;
join: string[];
update: string[];
// eslint-disable-next-line @typescript-eslint/no-explicit-any
insert: {[key: string]: any}[];
delete: boolean;
}
export interface QueryParams {
nest?: boolean;
details?: boolean;
split?: boolean;
comments?: boolean;
autocommit?: boolean;
schema?: string;
tabUid?: string;
}
/**
* @deprecated Use TableFIeld
*/
export type QueryField = TableField
export interface QueryForeign {
schema: string;
table: string;
field: string;
position: number;
constraintPosition: number;
constraintName: string;
refSchema: string;
refTable: string;
refField: string;
onUpdate: string;
onDelete: string;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export interface QueryResult<T = any> {
rows: T[];
report: { affectedRows: number };
fields: QueryField[];
keys: QueryForeign[];
duration: number;
}

View File

@@ -0,0 +1,98 @@
import { TypesGroup } from './antares';
export interface Customizations {
// Defaults
defaultPort?: number;
defaultUser?: string;
defaultDatabase?: string;
dataTypes?: TypesGroup[];
indexTypes?: string[];
foreignActions?: string[];
// Core
database?: boolean;
collations?: boolean;
engines?: boolean;
connectionSchema?: boolean;
sslConnection?: boolean;
sshConnection?: boolean;
fileConnection?: boolean;
cancelQueries?: boolean;
// Tools
processesList?: boolean;
usersManagement?: boolean;
variables?: boolean;
// Structure
schemas?: boolean;
tables?: boolean;
views?: boolean;
triggers?: boolean;
triggerFunctions?: boolean;
routines?: boolean;
functions?: boolean;
schedulers?: boolean;
// Settings
elementsWrapper: string;
stringsWrapper: string;
tableAdd?: boolean;
tableSettings?: boolean;
tableDuplicate?: boolean;
tableArray?: boolean;
tableRealCount?: boolean;
tableTruncateDisableFKCheck?: boolean;
viewAdd?: boolean;
viewSettings?: boolean;
triggerAdd?: boolean;
triggerFunctionAdd?: boolean;
routineAdd?: boolean;
functionAdd?: boolean;
schedulerAdd?: boolean;
databaseEdit?: boolean;
schemaEdit?: boolean;
schemaDrop?: boolean;
schemaExport?: boolean;
exportByChunks?: boolean;
schemaImport?: boolean;
triggerSettings?: boolean;
triggerFunctionSettings?: boolean;
routineSettings?: boolean;
functionSettings?: boolean;
schedulerSettings?: boolean;
indexes?: boolean;
foreigns?: boolean;
sortableFields?: boolean;
unsigned?: boolean;
nullable?: boolean;
nullablePrimary?: boolean;
zerofill?: boolean;
autoIncrement?: boolean;
comment?: boolean;
collation?: boolean;
definer?: boolean;
onUpdate?: boolean;
viewAlgorithm?: boolean;
viewSqlSecurity?: boolean;
viewUpdateOption?: boolean;
procedureDeterministic?: boolean;
procedureDataAccess?: boolean;
procedureSql?: string;
procedureContext?: boolean;
procedureContextValues?: string[];
procedureLanguage?: boolean;
functionDeterministic?: boolean;
functionDataAccess?: boolean;
functionSql?: string;
functionContext?: boolean;
functionLanguage?: boolean;
triggerSql?: string;
triggerStatementInCreation?: boolean;
triggerMultipleEvents?: boolean;
triggerTableInName?: boolean;
triggerUpdateColumns?: boolean;
triggerOnlyRename?: boolean;
triggerEnableDisable?: boolean;
triggerFunctionSql?: string;
triggerFunctionlanguages?: string[];
parametersLength?: boolean;
languages?: string[];
readOnlyMode?: boolean;
}

View File

@@ -0,0 +1,28 @@
export interface TableParams {
table: string;
includeStructure: boolean;
includeContent: boolean;
includeDropStatement: boolean;
}
export interface ExportOptions {
schema: string;
tables: {
table: string;
includeStructure: boolean;
includeContent: boolean;
includeDropStatement: boolean;
}[];
includes: {[key: string]: boolean};
outputFormat: 'sql' | 'sql.zip';
outputFile: string;
sqlInsertAfter: number;
sqlInsertDivider: 'bytes' | 'rows';
}
export interface ExportState {
totalItems?: number;
currentItemIndex?: number;
currentItem?: string;
op?: string;
}

View File

@@ -0,0 +1,16 @@
import * as antares from './antares';
export interface ImportOptions {
uid: string;
schema: string;
type: antares.ClientCode;
file: string;
}
export interface ImportState {
fileSize?: number;
readPosition?: number;
percentage?: number;
queryCount?: number;
op?: string;
}

View File

View File

@@ -0,0 +1,49 @@
import { UsableLocale } from '@faker-js/faker';
export interface TableUpdateParams {
uid: string;
schema: string;
table: string;
primary?: string;
id: number | string;
content: number | string | boolean | Date | Blob | null;
type: string;
field: string;
}
export interface TableDeleteParams {
uid: string;
schema: string;
table: string;
primary?: string;
field: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rows: {[key: string]: any};
}
export interface TableFilterClausole {
active: boolean;
field: string;
op: '=' | '!=' | '>' | '<' | '>=' | '<=' | 'IN' | 'NOT IN' | 'LIKE' | 'BETWEEN' | 'IS NULL' | 'IS NOT NULL';
value: '';
value2: '';
}
export interface InsertRowsParams {
uid: string;
schema: string;
table: string;
row: {[key: string]: {
group: string;
method: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
params: any;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value: any;
length: number;
};
};
repeat: number;
fields: {[key: string]: string};
locale: UsableLocale;
}

View File

@@ -0,0 +1,7 @@
export type WorkerEvent = 'export-progress' | 'import-progress' | 'query-error' | 'end' | 'cancel' | 'error'
export interface WorkerIpcMessage {
type: WorkerEvent;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
payload: any;
}

View File

@@ -1,7 +0,0 @@
'use strict';
export function bufferToBase64 (buf) {
const binstr = Array.prototype.map.call(buf, ch => {
return String.fromCharCode(ch);
}).join('');
return btoa(binstr);
}

View File

@@ -0,0 +1,6 @@
export function bufferToBase64 (buf: Buffer) {
const binstr = Array.prototype.map.call(buf, (ch: number) => {
return String.fromCharCode(ch);
}).join('');
return Buffer.from(binstr, 'binary').toString('base64');
}

View File

@@ -1,5 +1,4 @@
'use strict';
export function formatBytes (bytes, decimals = 2) {
export function formatBytes (bytes: number, decimals = 2) {
if (bytes === 0) return '0 Bytes';
const k = 1024;

View File

@@ -0,0 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
export function getArrayDepth (array: any[]): number {
return Array.isArray(array)
? 1 + Math.max(0, ...array.map(getArrayDepth))
: 0;
}

View File

@@ -1,5 +1,3 @@
'use strict';
const lookup = {
0: '0000',
1: '0001',
@@ -23,17 +21,13 @@ const lookup = {
D: '1101',
E: '1110',
F: '1111'
};
} as const;
/**
* Converts hexadecimal string to binary string
*
* @param {string} hex Hexadecimal string
* @returns {string} Binary string
*/
export default function hexToBinary (hex) {
export type HexChar = keyof typeof lookup
export default function hexToBinary (hex: HexChar[]) {
let binary = '';
for (let i = 0, len = hex.length; i < len; i++)
for (let i = 0; i < hex.length; i++)
binary += lookup[hex[i]];
return binary;

View File

@@ -0,0 +1,192 @@
function isJSON (str: string) {
try {
if (!['{', '['].includes(str.trim()[0]))
return false;
JSON.parse(str);
return true;
}
catch (_) {
return false;
}
}
function isHTML (str: string) {
const tags = [
'a',
'abbr',
'address',
'area',
'article',
'aside',
'audio',
'b',
'base',
'bdi',
'bdo',
'blockquote',
'body',
'br',
'button',
'canvas',
'caption',
'cite',
'code',
'col',
'colgroup',
'data',
'datalist',
'dd',
'del',
'details',
'dfn',
'dialog',
'div',
'dl',
'dt',
'em',
'embed',
'fieldset',
'figcaption',
'figure',
'footer',
'form',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'head',
'header',
'hgroup',
'hr',
'html',
'i',
'iframe',
'img',
'input',
'ins',
'kbd',
'label',
'legend',
'li',
'link',
'main',
'map',
'mark',
'math',
'menu',
'menuitem',
'meta',
'meter',
'nav',
'noscript',
'object',
'ol',
'optgroup',
'option',
'output',
'p',
'param',
'picture',
'pre',
'progress',
'q',
'rb',
'rp',
'rt',
'rtc',
'ruby',
's',
'samp',
'script',
'section',
'select',
'slot',
'small',
'source',
'span',
'strong',
'style',
'sub',
'summary',
'sup',
'svg',
'table',
'tbody',
'td',
'template',
'textarea',
'tfoot',
'th',
'thead',
'time',
'title',
'tr',
'track',
'u',
'ul',
'var',
'video',
'wbr'
];
const doc = new DOMParser().parseFromString(str, 'text/html');
const lowerStr = str.toLowerCase();
if (Array.from(doc.body.childNodes).some(node => node.nodeType === 1))
return tags.some((tag) => lowerStr.includes(`<${tag}>`));
return false;
}
function isSVG (str: string) {
const doc = new DOMParser().parseFromString(str, 'text/xml');
const lowerStr = str.toLowerCase();
const errorNode = doc.querySelector('parsererror');
if (!errorNode)
return lowerStr.includes('<svg');
return false;
}
function isXML (str: string) {
const doc = new DOMParser().parseFromString(str, 'text/xml');
const errorNode = doc.querySelector('parsererror');
return !errorNode;
}
function isMD (str: string) {
const mdChecks = [
'# ',
'`',
'- ',
'+ ',
'* ',
'1. ',
'**',
'__',
'~~',
'>> ',
'](http',
'![',
'[ ]',
'[x]'
];
return mdChecks.some((tag) => str.includes(tag));
}
export function langDetector (str: string) {
if (!str || !str.trim().length)
return 'text';
if (isJSON(str))
return 'json';
if (isHTML(str))
return 'html';
if (isSVG(str))
return 'svg';
if (isXML(str))
return 'xml';
if (isMD(str))
return 'markdown';
return 'text';
}

View File

@@ -1,5 +1,4 @@
'use strict';
export function mimeFromHex (hex) {
export function mimeFromHex (hex: string) {
switch (hex.substring(0, 4)) { // 2 bytes
case '424D':
return { ext: 'bmp', mime: 'image/bmp' };
@@ -43,4 +42,4 @@ export function mimeFromHex (hex) {
}
}
}
};
}

View File

@@ -1,20 +0,0 @@
/* eslint-disable no-useless-escape */
// eslint-disable-next-line no-control-regex
const pattern = /[\0\x08\x09\x1a\n\r"'\\\%]/gm;
const regex = new RegExp(pattern);
/**
* Escapes a string
*
* @param {String} string
* @returns {String}
*/
function sqlEscaper (string) {
return string.replace(regex, char => {
const m = ['\\0', '\\x08', '\\x09', '\\x1a', '\\n', '\\r', '\'', '\"', '\\', '\\\\', '%'];
const r = ['\\\\0', '\\\\b', '\\\\t', '\\\\z', '\\\\n', '\\\\r', '\\\'', '\\\"', '\\\\', '\\\\\\\\', '\%'];
return r[m.indexOf(char)] || char;
});
}
export { sqlEscaper };

162
src/common/libs/sqlUtils.ts Normal file
View File

@@ -0,0 +1,162 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable no-useless-escape */
import * as moment from 'moment';
import { lineString, point, polygon } from '@turf/helpers';
import customizations from '../customizations';
import { ClientCode } from '../interfaces/antares';
import { BLOB, BIT, DATE, DATETIME, FLOAT, SPATIAL, IS_MULTI_SPATIAL, NUMBER, TEXT_SEARCH } from 'common/fieldTypes';
import hexToBinary, { HexChar } from './hexToBinary';
import { getArrayDepth } from './getArrayDepth';
/**
* Escapes a string fo SQL use
*
* @param { String } string
* @returns { String } Escaped string
*/
export const sqlEscaper = (string: string): string => {
// eslint-disable-next-line no-control-regex
const pattern = /[\0\x08\x09\x1a\n\r"'\\\%]/gm;
const regex = new RegExp(pattern);
return string.replace(regex, char => {
const m = ['\\0', '\\x08', '\\x09', '\\x1a', '\\n', '\\r', '\'', '\"', '\\', '\\\\', '%'];
const r = ['\\\\0', '\\\\b', '\\\\t', '\\\\z', '\\\\n', '\\\\r', '\\\'', '\\\"', '\\\\', '\\\\\\\\', '\%'];
return r[m.indexOf(char)] || char;
});
};
export const objectToGeoJSON = (val: any) => {
if (Array.isArray(val)) {
if (getArrayDepth(val) === 1)
return lineString(val.reduce((acc, curr) => [...acc, [curr.x, curr.y]], []));
else
return polygon(val.map(arr => arr.reduce((acc: any, curr: any) => [...acc, [curr.x, curr.y]], [])));
}
else
return point([val.x, val.y]);
};
export const escapeAndQuote = (val: string, client: ClientCode) => {
const { stringsWrapper: sw } = customizations[client];
// eslint-disable-next-line no-control-regex
const CHARS_TO_ESCAPE = /[\0\b\t\n\r\x1a"'\\]/g;
const CHARS_ESCAPE_MAP: {[key: string]: string} = {
'\0': '\\0',
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\r': '\\r',
'\x1a': '\\Z',
'"': '\\"',
'\'': '\\\'',
'\\': '\\\\'
};
let chunkIndex = CHARS_TO_ESCAPE.lastIndex = 0;
let escapedVal = '';
let match;
while ((match = CHARS_TO_ESCAPE.exec(val))) {
escapedVal += val.slice(chunkIndex, match.index) + CHARS_ESCAPE_MAP[match[0]];
chunkIndex = CHARS_TO_ESCAPE.lastIndex;
}
if (chunkIndex === 0)
return `${sw}${val}${sw}`;
if (chunkIndex < val.length)
return `${sw}${escapedVal + val.slice(chunkIndex)}${sw}`;
return `${sw}${escapedVal}${sw}`;
};
export const valueToSqlString = (args: {
val: any;
client: ClientCode;
field: {type: string; datePrecision: number};
}): string => {
let parsedValue;
const { val, client, field } = args;
const { stringsWrapper: sw } = customizations[client];
if (val === null)
parsedValue = 'NULL';
else if (DATE.includes(field.type)) {
parsedValue = moment(val).isValid()
? escapeAndQuote(moment(val).format('YYYY-MM-DD'), client)
: val;
}
else if (DATETIME.includes(field.type)) {
let datePrecision = '';
for (let i = 0; i < field.datePrecision; i++)
datePrecision += i === 0 ? '.S' : 'S';
parsedValue = moment(val).isValid()
? escapeAndQuote(moment(val).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`), client)
: escapeAndQuote(val, client);
}
else if ('isArray' in field) {
let localVal;
if (Array.isArray(val))
localVal = JSON.stringify(val).replaceAll('[', '{').replaceAll(']', '}');
else
localVal = typeof val === 'string' ? val.replaceAll('[', '{').replaceAll(']', '}') : '';
parsedValue = `'${localVal}'`;
}
else if (TEXT_SEARCH.includes(field.type))
parsedValue = `'${val.replaceAll('\'', '\'\'')}'`;
else if (BIT.includes(field.type))
parsedValue = `b'${hexToBinary(Buffer.from(val).toString('hex') as undefined as HexChar[])}'`;
else if (BLOB.includes(field.type)) {
if (['mysql', 'maria'].includes(client))
parsedValue = `X'${val.toString('hex').toUpperCase()}'`;
else if (client === 'pg')
parsedValue = `decode('${val.toString('hex').toUpperCase()}', 'hex')`;
}
else if (NUMBER.includes(field.type))
parsedValue = val;
else if (FLOAT.includes(field.type))
parsedValue = parseFloat(val);
else if (SPATIAL.includes(field.type)) {
let geoJson;
if (IS_MULTI_SPATIAL.includes(field.type)) {
const features = [];
for (const element of val)
features.push(objectToGeoJSON(element));
geoJson = {
type: 'FeatureCollection',
features
};
}
else
geoJson = objectToGeoJSON(val);
parsedValue = `ST_GeomFromGeoJSON('${JSON.stringify(geoJson)}')`;
}
else if (val === '') parsedValue = `${sw}${sw}`;
else {
parsedValue = typeof val === 'string'
? escapeAndQuote(val, client)
: typeof val === 'object'
? escapeAndQuote(JSON.stringify(val), client)
: val;
}
return parsedValue;
};
export const jsonToSqlInsert = (args: {
json: { [key: string]: any};
client: ClientCode;
fields: { [key: string]: {type: string; datePrecision: number}};
table: string;
}) => {
const { client, json, fields, table } = args;
const { elementsWrapper: ew } = customizations[client];
const fieldNames = Object.keys(json).map(key => `${ew}${key}${ew}`);
const values = Object.keys(json).map(key => (
valueToSqlString({ val: json[key], client, field: fields[key] })
));
return `INSERT INTO ${ew}${table}${ew} (${fieldNames.join(', ')}) VALUES (${values.join(', ')});`;
};

View File

@@ -1,8 +0,0 @@
/**
* @export
* @param {String} [prefix]
* @returns {String} Unique ID
*/
export function uidGen (prefix) {
return (prefix ? `${prefix}:` : '') + Math.random().toString(36).substr(2, 9).toUpperCase();
};

View File

@@ -0,0 +1,3 @@
export function uidGen (prefix?: string) {
return (prefix ? `${prefix}:` : '') + Math.random().toString(36).substring(2, 11).toUpperCase();
}

138
src/common/shortcuts.ts Normal file
View File

@@ -0,0 +1,138 @@
export const shortcutEvents: { [key: string]: { l18n: string; l18nParam?: string | number; context?: 'tab' }} = {
'run-or-reload': { l18n: 'message.runOrReload', context: 'tab' },
'open-new-tab': { l18n: 'message.openNewTab', context: 'tab' },
'close-tab': { l18n: 'message.closeTab', context: 'tab' },
'format-query': { l18n: 'message.formatQuery', context: 'tab' },
'kill-query': { l18n: 'message.killQuery', context: 'tab' },
'query-history': { l18n: 'message.queryHistory', context: 'tab' },
'clear-query': { l18n: 'message.clearQuery', context: 'tab' },
'next-tab': { l18n: 'message.nextTab' },
'prev-tab': { l18n: 'message.previousTab' },
'open-all-connections': { l18n: 'message.openAllConnections' },
'open-filter': { l18n: 'message.openFilter' },
'next-page': { l18n: 'message.nextResultsPage' },
'prev-page': { l18n: 'message.previousResultsPage' },
'toggle-console': { l18n: 'message.toggleConsole' },
'save-content': { l18n: 'message.saveContent' },
'create-connection': { l18n: 'message.createNewConnection' },
'open-settings': { l18n: 'message.openSettings' },
'open-scratchpad': { l18n: 'message.openScratchpad' }
};
interface ShortcutRecord {
event: string;
keys: Electron.Accelerator[] | string[];
/** Needed for default shortcuts */
os: NodeJS.Platform[];
}
/**
* Default shortcuts
*/
const shortcuts: ShortcutRecord[] = [
{
event: 'run-or-reload',
keys: ['F5'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'save-content',
keys: ['CommandOrControl+S'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'kill-query',
keys: ['CommandOrControl+K'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'format-query',
keys: ['CommandOrControl+B'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'clear-query',
keys: ['CommandOrControl+Alt+W'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'query-history',
keys: ['CommandOrControl+G'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'open-new-tab',
keys: ['CommandOrControl+T'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'close-tab',
keys: ['CommandOrControl+W'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'next-tab',
keys: ['Alt+CommandOrControl+Right'],
os: ['darwin', 'win32']
},
{
event: 'prev-tab',
keys: ['Alt+CommandOrControl+Left'],
os: ['darwin', 'win32']
},
{
event: 'next-tab',
keys: ['CommandOrControl+PageDown'],
os: ['linux', 'win32']
},
{
event: 'prev-tab',
keys: ['CommandOrControl+PageUp'],
os: ['linux', 'win32']
},
{
event: 'open-filter',
keys: ['CommandOrControl+F'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'next-page',
keys: ['CommandOrControl+Right'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'prev-page',
keys: ['CommandOrControl+Left'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'open-all-connections',
keys: ['Shift+CommandOrControl+Space'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'toggle-console',
keys: ['CommandOrControl+F12'],
os: ['darwin', 'linux', 'win32']
},
{
event: 'toggle-console',
keys: ['CommandOrControl+`'],
os: ['darwin', 'linux', 'win32']
}
];
for (let i = 1; i <= 9; i++) {
shortcutEvents[`select-tab-${i}`] = {
l18n: 'message.selectTabNumber',
l18nParam: i
};
shortcuts.push({
event: `select-tab-${i}`,
keys: [`CommandOrControl+${i}`],
os: ['darwin', 'linux', 'win32']
});
}
export { shortcuts, ShortcutRecord };

View File

@@ -1,12 +0,0 @@
import { app, ipcMain } from 'electron';
export default () => {
ipcMain.on('close-app', () => {
app.exit();
});
ipcMain.on('get-key', async event => {
const key = false;
event.returnValue = key;
});
};

View File

@@ -0,0 +1,36 @@
import { app, ipcMain, dialog } from 'electron';
import { ShortcutRegister } from '../libs/ShortcutRegister';
export default () => {
ipcMain.on('close-app', () => {
app.exit();
});
ipcMain.handle('show-open-dialog', (event, options) => {
return dialog.showOpenDialog(options);
});
ipcMain.handle('get-download-dir-path', () => {
return app.getPath('downloads');
});
ipcMain.handle('resotre-default-shortcuts', () => {
const shortCutRegister = ShortcutRegister.getInstance();
shortCutRegister.restoreDefaults();
});
ipcMain.handle('reload-shortcuts', () => {
const shortCutRegister = ShortcutRegister.getInstance();
shortCutRegister.reload();
});
ipcMain.handle('update-shortcuts', (event, shortcuts) => {
const shortCutRegister = ShortcutRegister.getInstance();
shortCutRegister.updateShortcuts(shortcuts);
});
ipcMain.handle('unregister-shortcuts', () => {
const shortCutRegister = ShortcutRegister.getInstance();
shortCutRegister.unregister();
});
};

View File

@@ -1,16 +1,29 @@
import fs from 'fs';
import * as antares from 'common/interfaces/antares';
import * as fs from 'fs';
import { ipcMain } from 'electron';
import { ClientsFactory } from '../libs/ClientsFactory';
import { SslOptions } from 'mysql2';
export default connections => {
ipcMain.handle('test-connection', async (event, conn) => {
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('test-connection', async (event, conn: antares.ConnectionParams) => {
const params = {
host: conn.host,
port: +conn.port,
user: conn.user,
password: conn.password,
application_name: 'Antares SQL',
readonly: conn.readonly
readonly: conn.readonly,
database: '',
schema: '',
databasePath: '',
ssl: undefined as SslOptions,
ssh: undefined as {
host: string;
username: string;
password: string;
port: number;
privateKey: string;
passphrase: string;
}
};
if (conn.database)
@@ -21,10 +34,11 @@ export default connections => {
if (conn.ssl) {
params.ssl = {
key: conn.key ? fs.readFileSync(conn.key) : null,
cert: conn.cert ? fs.readFileSync(conn.cert) : null,
ca: conn.ca ? fs.readFileSync(conn.ca) : null,
ciphers: conn.ciphers
key: conn.key ? fs.readFileSync(conn.key).toString() : null,
cert: conn.cert ? fs.readFileSync(conn.cert).toString() : null,
ca: conn.ca ? fs.readFileSync(conn.ca).toString() : null,
ciphers: conn.ciphers,
rejectUnauthorized: !conn.untrustedConnection
};
}
@@ -34,19 +48,24 @@ export default connections => {
username: conn.sshUser,
password: conn.sshPass,
port: conn.sshPort ? conn.sshPort : 22,
privateKey: conn.sshKey ? fs.readFileSync(conn.sshKey) : null,
privateKey: conn.sshKey ? fs.readFileSync(conn.sshKey).toString() : null,
passphrase: conn.sshPassphrase
};
}
try {
const connection = await ClientsFactory.getConnection({
const connection = await ClientsFactory.getClient({
uid: conn.uid,
client: conn.client,
params
});
await connection.connect();
await connection.select('1+1').run();
if (conn.client === 'firebird')
connection.raw('SELECT rdb$get_context(\'SYSTEM\', \'DB_NAME\') FROM rdb$database');
else
await connection.select('1+1').run();
connection.destroy();
return { status: 'success' };
@@ -60,14 +79,26 @@ export default connections => {
return uid in connections;
});
ipcMain.handle('connect', async (event, conn) => {
ipcMain.handle('connect', async (event, conn: antares.ConnectionParams) => {
const params = {
host: conn.host,
port: +conn.port,
user: conn.user,
password: conn.password,
application_name: 'Antares SQL',
readonly: conn.readonly
readonly: conn.readonly,
database: '',
schema: '',
databasePath: '',
ssl: undefined as SslOptions,
ssh: undefined as {
host: string;
username: string;
password: string;
port: number;
privateKey: string;
passphrase: string;
}
};
if (conn.database)
@@ -81,10 +112,11 @@ export default connections => {
if (conn.ssl) {
params.ssl = {
key: conn.key ? fs.readFileSync(conn.key) : null,
cert: conn.cert ? fs.readFileSync(conn.cert) : null,
ca: conn.ca ? fs.readFileSync(conn.ca) : null,
ciphers: conn.ciphers
key: conn.key ? fs.readFileSync(conn.key).toString() : null,
cert: conn.cert ? fs.readFileSync(conn.cert).toString() : null,
ca: conn.ca ? fs.readFileSync(conn.ca).toString() : null,
ciphers: conn.ciphers,
rejectUnauthorized: !conn.untrustedConnection
};
}
@@ -94,13 +126,14 @@ export default connections => {
username: conn.sshUser,
password: conn.sshPass,
port: conn.sshPort ? conn.sshPort : 22,
privateKey: conn.sshKey ? fs.readFileSync(conn.sshKey) : null,
privateKey: conn.sshKey ? fs.readFileSync(conn.sshKey).toString() : null,
passphrase: conn.sshPassphrase
};
}
try {
const connection = ClientsFactory.getConnection({
const connection = ClientsFactory.getClient({
uid: conn.uid,
client: conn.client,
params,
poolSize: 5

View File

@@ -1,6 +1,7 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
export default (connections) => {
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-function-informations', async (event, params) => {
try {
const result = await connections[params.uid].getFunctionInformations(params);

View File

@@ -1,3 +1,5 @@
import * as antares from 'common/interfaces/antares';
import connection from './connection';
import tables from './tables';
import views from './views';
@@ -10,7 +12,7 @@ import application from './application';
import schema from './schema';
import users from './users';
const connections = {};
const connections: {[key: string]: antares.Client} = {};
export default () => {
connection(connections);

View File

@@ -1,6 +1,7 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
export default (connections) => {
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-routine-informations', async (event, params) => {
try {
const result = await connections[params.uid].getRoutineInformations(params);

View File

@@ -1,6 +1,7 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
export default (connections) => {
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-scheduler-informations', async (event, params) => {
try {
const result = await connections[params.uid].getEventInformations(params);

View File

@@ -1,155 +0,0 @@
import { ipcMain } from 'electron';
export default connections => {
ipcMain.handle('create-schema', async (event, params) => {
try {
await connections[params.uid].createSchema(params);
return { status: 'success' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('update-schema', async (event, params) => {
try {
await connections[params.uid].alterSchema(params);
return { status: 'success' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('delete-schema', async (event, params) => {
try {
await connections[params.uid].dropSchema(params);
return { status: 'success' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-schema-collation', async (event, params) => {
try {
const collation = await connections[params.uid].getDatabaseCollation(params);
return { status: 'success', response: collation.rows.length ? collation.rows[0].DEFAULT_COLLATION_NAME : '' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-structure', async (event, params) => {
try {
const structure = await connections[params.uid].getStructure(params.schemas);
return { status: 'success', response: structure };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-collations', async (event, uid) => {
try {
const result = await connections[uid].getCollations();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-variables', async (event, uid) => {
try {
const result = await connections[uid].getVariables();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-engines', async (event, uid) => {
try {
const result = await connections[uid].getEngines();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-version', async (event, uid) => {
try {
const result = await connections[uid].getVersion();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-processes', async (event, uid) => {
try {
const result = await connections[uid].getProcesses();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('kill-process', async (event, { uid, pid }) => {
try {
const result = await connections[uid].killProcess(pid);
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('use-schema', async (event, { uid, schema }) => {
if (!schema) return;
try {
await connections[uid].use(schema);
return { status: 'success' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('raw-query', async (event, { uid, query, schema }) => {
if (!query) return;
try {
const result = await connections[uid].raw(query, {
nest: true,
details: true,
schema,
comments: false
});
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
};

View File

@@ -0,0 +1,389 @@
import * as antares from 'common/interfaces/antares';
import * as workers from 'common/interfaces/workers';
import * as fs from 'fs';
import * as path from 'path';
import { ChildProcess, fork } from 'child_process';
import { ipcMain, dialog } from 'electron';
const isDevelopment = process.env.NODE_ENV !== 'production';
export default (connections: {[key: string]: antares.Client}) => {
let exporter: ChildProcess = null;
let importer: ChildProcess = null;
ipcMain.handle('create-schema', async (event, params) => {
try {
await connections[params.uid].createSchema(params);
return { status: 'success' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('update-schema', async (event, params) => {
try {
await connections[params.uid].alterSchema(params);
return { status: 'success' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('delete-schema', async (event, params) => {
try {
await connections[params.uid].dropSchema(params);
return { status: 'success' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-schema-collation', async (event, params) => {
try {
const collation = await connections[params.uid].getDatabaseCollation(
params
);
return {
status: 'success',
response: collation
};
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-structure', async (event, params) => {
try {
const structure: unknown = await connections[params.uid].getStructure(
params.schemas
);
return { status: 'success', response: structure };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-collations', async (event, uid) => {
try {
const result = await connections[uid].getCollations();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-variables', async (event, uid) => {
try {
const result = await connections[uid].getVariables();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-engines', async (event, uid) => {
try {
const result: unknown = await connections[uid].getEngines();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-version', async (event, uid) => {
try {
const result = await connections[uid].getVersion();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('get-processes', async (event, uid) => {
try {
const result = await connections[uid].getProcesses();
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('kill-process', async (event, { uid, pid }) => {
try {
const result = await connections[uid].killProcess(pid);
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('use-schema', async (event, { uid, schema }) => {
if (!schema) return;
try {
await connections[uid].use(schema);
return { status: 'success' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('raw-query', async (event, { uid, query, schema, tabUid, autocommit }) => {
if (!query) return;
try {
const result = await connections[uid].raw(query, {
nest: true,
details: true,
schema,
tabUid,
autocommit
});
return { status: 'success', response: result };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('export', (event, { uid, type, tables, ...rest }) => {
if (exporter !== null) {
exporter.kill();
return;
}
return new Promise((resolve/*, reject */) => {
(async () => {
if (fs.existsSync(rest.outputFile)) { // If file exists ask for replace
const result = await dialog.showMessageBox({
type: 'warning',
message: `File ${rest.outputFile} already exists. Do you want to replace it?`,
detail: 'A file with the same name already exists in the target folder. Replacing it will overwrite its current contents.',
buttons: ['Cancel', 'Replace'],
defaultId: 0,
cancelId: 0
});
if (result.response !== 1) {
resolve({
type: 'error',
response: 'Operation aborted'
});
return;
}
}
// Init exporter process
exporter = fork(isDevelopment ? './dist/exporter.js' : path.resolve(__dirname, './exporter.js'), [], {
execArgv: isDevelopment ? ['--inspect=9224'] : undefined
});
exporter.send({
type: 'init',
client: {
name: type,
config: await connections[uid].getDbConfig()
},
tables,
options: rest
});
// Exporter message listener
exporter.on('message', ({ type, payload }: workers.WorkerIpcMessage) => {
switch (type) {
case 'export-progress':
event.sender.send('export-progress', payload);
break;
case 'end':
setTimeout(() => { // Ensures that writing process has finished
exporter.kill();
exporter = null;
}, 2000);
resolve({ status: 'success', response: payload });
break;
case 'cancel':
exporter.kill();
exporter = null;
resolve({ status: 'error', response: 'Operation cancelled' });
break;
case 'error':
exporter.kill();
exporter = null;
resolve({ status: 'error', response: payload });
break;
}
});
exporter.on('exit', code => {
exporter = null;
resolve({ status: 'error', response: `Operation ended with code: ${code}` });
});
})();
});
});
ipcMain.handle('abort-export', async () => {
let willAbort = false;
if (exporter) {
const result = await dialog.showMessageBox({
type: 'warning',
message: 'Are you sure you want to abort the export',
buttons: ['Cancel', 'Abort'],
defaultId: 0,
cancelId: 0
});
if (result.response === 1) {
willAbort = true;
exporter.send({ type: 'cancel' });
}
}
return { status: 'success', response: { willAbort } };
});
ipcMain.handle('import-sql', async (event, options) => {
if (importer !== null) {
importer.kill();
return;
}
return new Promise((resolve/*, reject */) => {
(async () => {
const dbConfig = await connections[options.uid].getDbConfig();
// Init importer process
importer = fork(isDevelopment ? './dist/importer.js' : path.resolve(__dirname, './importer.js'), [], {
execArgv: isDevelopment ? ['--inspect=9224'] : undefined
});
importer.send({
type: 'init',
dbConfig,
options
});
// Importer message listener
importer.on('message', ({ type, payload }: workers.WorkerIpcMessage) => {
switch (type) {
case 'import-progress':
event.sender.send('import-progress', payload);
break;
case 'query-error':
event.sender.send('query-error', payload);
break;
case 'end':
setTimeout(() => { // Ensures that writing process has finished
importer?.kill();
importer = null;
}, 2000);
resolve({ status: 'success', response: payload });
break;
case 'cancel':
importer.kill();
importer = null;
resolve({ status: 'error', response: 'Operation cancelled' });
break;
case 'error':
importer.kill();
importer = null;
resolve({ status: 'error', response: payload });
break;
}
});
})();
});
});
ipcMain.handle('abort-import-sql', async () => {
let willAbort = false;
if (importer) {
const result = await dialog.showMessageBox({
type: 'warning',
message: 'Are you sure you want to abort the import',
buttons: ['Cancel', 'Abort'],
defaultId: 0,
cancelId: 0
});
if (result.response === 1) {
willAbort = true;
importer.send({ type: 'cancel' });
}
}
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() };
}
});
};

View File

@@ -1,12 +1,14 @@
import * as fs from 'fs';
import * as antares from 'common/interfaces/antares';
import { InsertRowsParams } from 'common/interfaces/tableApis';
import { ipcMain } from 'electron';
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';
import { faker } from '@faker-js/faker';
import * as moment from 'moment';
import { sqlEscaper } from 'common/libs/sqlUtils';
import { TEXT, LONG_TEXT, ARRAY, TEXT_SEARCH, NUMBER, FLOAT, BLOB, BIT, DATE, DATETIME, BOOLEAN } from 'common/fieldTypes';
import customizations from 'common/customizations';
export default (connections) => {
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-table-columns', async (event, params) => {
try {
const result = await connections[params.uid].getTableColumns(params);
@@ -102,9 +104,8 @@ export default (connections) => {
escapedParam = `"${sqlEscaper(params.content)}"`;
break;
case 'pg':
escapedParam = `'${params.content.replaceAll('\'', '\'\'')}'`;
break;
case 'sqlite':
case 'firebird':
escapedParam = `'${params.content.replaceAll('\'', '\'\'')}'`;
break;
}
@@ -124,6 +125,7 @@ export default (connections) => {
escapedParam = `0x${fileBlob.toString('hex')}`;
break;
case 'pg':
case 'firebird':
fileBlob = fs.readFileSync(params.content);
escapedParam = `decode('${fileBlob.toString('hex')}', 'hex')`;
break;
@@ -141,6 +143,7 @@ export default (connections) => {
escapedParam = '\'\'';
break;
case 'pg':
case 'firebird':
escapedParam = 'decode(\'\', \'hex\')';
break;
case 'sqlite':
@@ -149,10 +152,23 @@ export default (connections) => {
}
}
}
else if ([...BIT].includes(params.type)) {
else if (BIT.includes(params.type)) {
escapedParam = `b'${sqlEscaper(params.content)}'`;
reload = true;
}
else if (BOOLEAN.includes(params.type)) {
switch (connections[params.uid]._client) {
case 'mysql':
case 'maria':
case 'pg':
case 'firebird':
escapedParam = params.content;
break;
case 'sqlite':
escapedParam = Number(params.content === 'true');
break;
}
}
else if (params.content === null)
escapedParam = 'NULL';
else
@@ -169,13 +185,18 @@ export default (connections) => {
}
else {
const { orgRow } = params;
delete orgRow._antares_id;
reload = true;
for (const key in orgRow) {
if (typeof orgRow[key] === 'string')
orgRow[key] = `'${orgRow[key]}'`;
orgRow[key] = `= ${orgRow[key]}`;
if (orgRow[key] === null)
orgRow[key] = `IS ${orgRow[key]}`;
else
orgRow[key] = `= ${orgRow[key]}`;
}
await connections[params.uid]
@@ -196,7 +217,8 @@ export default (connections) => {
ipcMain.handle('delete-table-rows', async (event, params) => {
if (params.primary) {
const idString = params.rows.map(row => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const idString = params.rows.map((row: {[key: string]: any}) => {
const fieldName = Object.keys(row)[0].includes('.') ? `${params.table}.${params.primary}` : params.primary;
return typeof row[fieldName] === 'string'
@@ -205,10 +227,11 @@ export default (connections) => {
}).join(',');
try {
const result = await connections[params.uid]
const result: unknown = await connections[params.uid]
.schema(params.schema)
.delete(params.table)
.where({ [params.primary]: `IN (${idString})` })
.limit(params.rows.length)
.run();
return { status: 'success', response: result };
@@ -243,81 +266,12 @@ export default (connections) => {
}
});
ipcMain.handle('insert-table-rows', async (event, params) => {
ipcMain.handle('insert-table-fake-rows', async (event, params: InsertRowsParams) => {
try { // TODO: move to client classes
const insertObj = {};
for (const key in params.row) {
const type = params.fields[key];
let escapedParam;
if (params.row[key] === null)
escapedParam = 'NULL';
else if ([...NUMBER, ...FLOAT].includes(type))
escapedParam = +params.row[key];
else if ([...TEXT, ...LONG_TEXT].includes(type)) {
switch (connections[params.uid]._client) {
case 'mysql':
case 'maria':
escapedParam = `"${sqlEscaper(params.row[key].value)}"`;
break;
case 'pg':
escapedParam = `'${params.row[key].value.replaceAll('\'', '\'\'')}'`;
break;
}
}
else if (BLOB.includes(type)) {
if (params.row[key].value) {
let fileBlob;
switch (connections[params.uid]._client) {
case 'mysql':
case 'maria':
fileBlob = fs.readFileSync(params.row[key].value);
escapedParam = `0x${fileBlob.toString('hex')}`;
break;
case 'pg':
fileBlob = fs.readFileSync(params.row[key].value);
escapedParam = `decode('${fileBlob.toString('hex')}', 'hex')`;
break;
}
}
else {
switch (connections[params.uid]._client) {
case 'mysql':
case 'maria':
escapedParam = '""';
break;
case 'pg':
escapedParam = 'decode(\'\', \'hex\')';
break;
}
}
}
insertObj[key] = escapedParam;
}
const rows = new Array(+params.repeat).fill(insertObj);
await connections[params.uid]
.schema(params.schema)
.into(params.table)
.insert(rows)
.run();
return { status: 'success' };
}
catch (err) {
return { status: 'error', response: err.toString() };
}
});
ipcMain.handle('insert-table-fake-rows', async (event, params) => {
try { // TODO: move to client classes
const rows = [];
const rows: {[key: string]: string | number | boolean | Date | Buffer}[] = [];
for (let i = 0; i < +params.repeat; i++) {
const insertObj = {};
const insertObj: {[key: string]: string | number | boolean | Date | Buffer} = {};
for (const key in params.row) {
const type = params.fields[key];
@@ -335,6 +289,8 @@ export default (connections) => {
escapedParam = `"${sqlEscaper(params.row[key].value)}"`;
break;
case 'pg':
case 'sqlite':
case 'firebird':
escapedParam = `'${params.row[key].value.replaceAll('\'', '\'\'')}'`;
break;
}
@@ -375,7 +331,7 @@ export default (connections) => {
insertObj[key] = escapedParam;
}
else { // Faker value
const parsedParams = {};
const parsedParams: {[key: string]: string | number | boolean | Date | Buffer} = {};
let fakeValue;
if (params.locale)
@@ -386,15 +342,28 @@ export default (connections) => {
if (!isNaN(params.row[key].params[param]))
parsedParams[param] = +params.row[key].params[param];
});
fakeValue = faker[params.row[key].group][params.row[key].method](parsedParams);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fakeValue = (faker as any)[params.row[key].group][params.row[key].method](parsedParams);
}
else
fakeValue = faker[params.row[key].group][params.row[key].method]();
// eslint-disable-next-line @typescript-eslint/no-explicit-any
fakeValue = (faker as any)[params.row[key].group][params.row[key].method]();
if (typeof fakeValue === 'string') {
if (params.row[key].length)
fakeValue = fakeValue.substr(0, params.row[key].length);
fakeValue = `'${sqlEscaper(fakeValue)}'`;
fakeValue = fakeValue.substring(0, params.row[key].length);
switch (connections[params.uid]._client) {
case 'mysql':
case 'maria':
fakeValue = `'${sqlEscaper(fakeValue)}'`;
break;
case 'pg':
case 'sqlite':
case 'firebird':
fakeValue = `'${fakeValue.replaceAll('\'', '\'\'')}'`;
break;
}
}
else if ([...DATE, ...DATETIME].includes(type))
fakeValue = `'${moment(fakeValue).format('YYYY-MM-DD HH:mm:ss.SSSSSS')}'`;
@@ -430,7 +399,20 @@ export default (connections) => {
if (description)
query.select(`LEFT(${description}, 20) AS foreign_description`);
const results = await query.run();
const results = await query.run<{[key: string]: string}>();
const parsedResults: {[key: string]: string}[] = [];
for (const row of results.rows) {
const remappedRow: {[key: string]: string} = {};
for (const key in row)
remappedRow[key.toLowerCase()] = row[key];// Thanks Firebird -.-
parsedResults.push(remappedRow);
}
results.rows = parsedResults;
return { status: 'success', response: results };
}

View File

@@ -1,6 +1,7 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
export default (connections) => {
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-trigger-informations', async (event, params) => {
try {
const result = await connections[params.uid].getTriggerInformations(params);

View File

@@ -1,11 +1,11 @@
import { ipcMain } from 'electron';
import { autoUpdater } from 'electron-updater';
import Store from 'electron-store';
const persistentStore = new Store({ name: 'settings' });
import * as Store from 'electron-store';
const persistentStore = new Store({ name: 'settings', clearInvalidConfig: true });
const isMacOS = process.platform === 'darwin';
let mainWindow;
autoUpdater.allowPrerelease = persistentStore.get('allow_prerelease', true);
let mainWindow: Electron.IpcMainEvent;
autoUpdater.allowPrerelease = persistentStore.get('allow_prerelease', true) as boolean;
export default () => {
ipcMain.on('check-for-updates', event => {
@@ -50,7 +50,7 @@ export default () => {
mainWindow.reply('update-downloaded');
});
autoUpdater.logger = require('electron-log');
autoUpdater.logger.transports.console.format = '{h}:{i}:{s} {text}';
autoUpdater.logger.transports.file.level = 'info';
// autoUpdater.logger = require('electron-log');
// autoUpdater.logger.transports.console.format = '{h}:{i}:{s} {text}';
// autoUpdater.logger.transports.file.level = 'info';
};

View File

@@ -1,6 +1,7 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
export default (connections) => {
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-users', async (event, uid) => {
try {
const result = await connections[uid].getUsers();

View File

@@ -1,6 +1,7 @@
import * as antares from 'common/interfaces/antares';
import { ipcMain } from 'electron';
export default (connections) => {
export default (connections: {[key: string]: antares.Client}) => {
ipcMain.handle('get-view-informations', async (event, params) => {
try {
const result = await connections[params.uid].getViewInformations(params);

View File

@@ -1,149 +0,0 @@
'use strict';
/**
* As Simple As Possible Query Builder Core
*
* @class AntaresCore
*/
export class AntaresCore {
/**
* Creates an instance of AntaresCore.
*
* @param {Object} args connection params
* @memberof AntaresCore
*/
constructor (args) {
this._client = args.client;
this._params = args.params;
this._poolSize = args.poolSize || false;
this._connection = null;
this._ssh = null;
this._logger = args.logger || console.log;
this._queryDefaults = {
schema: '',
select: [],
from: '',
where: [],
groupBy: [],
orderBy: [],
limit: [],
offset: [],
join: [],
update: [],
insert: [],
delete: false
};
this._query = Object.assign({}, this._queryDefaults);
}
_reducer (acc, curr) {
const type = typeof curr;
switch (type) {
case 'number':
case 'string':
return [...acc, curr];
case 'object':
if (Array.isArray(curr))
return [...acc, ...curr];
else {
const clausoles = [];
for (const key in curr)
clausoles.push(`${key} ${curr[key]}`);
return clausoles;
}
}
}
/**
* Resets the query object after a query
*
* @memberof AntaresCore
*/
_resetQuery () {
this._query = Object.assign({}, this._queryDefaults);
}
schema (schema) {
this._query.schema = schema;
return this;
}
select (...args) {
this._query.select = [...this._query.select, ...args];
return this;
}
from (table) {
this._query.from = table;
return this;
}
into (table) {
this._query.from = table;
return this;
}
delete (table) {
this._query.delete = true;
this.from(table);
return this;
}
where (...args) {
this._query.where = [...this._query.where, ...args];
return this;
}
groupBy (...args) {
this._query.groupBy = [...this._query.groupBy, ...args];
return this;
}
orderBy (...args) {
this._query.orderBy = [...this._query.orderBy, ...args];
return this;
}
limit (...args) {
this._query.limit = args;
return this;
}
offset (...args) {
this._query.offset = args;
return this;
}
/**
* @param {String | Array} args field = value
* @returns
* @memberof AntaresCore
*/
update (...args) {
this._query.update = [...this._query.update, ...args];
return this;
}
/**
* @param {Array} arr Array of row objects
* @returns
* @memberof AntaresCore
*/
insert (arr) {
this._query.insert = [...this._query.insert, ...arr];
return this;
}
/**
* @param {Object} args
* @returns {Promise}
* @memberof AntaresCore
*/
run (args) {
const rawQuery = this.getSQL();
this._resetQuery();
return this.raw(rawQuery, args);
}
}

View File

@@ -0,0 +1,266 @@
import * as antares from 'common/interfaces/antares';
import mysql from 'mysql2/promise';
import * as pg from 'pg';
import SSH2Promise from 'ssh2-promise';
const queryLogger = ({ sql, cUid }: {sql: string; cUid: string}) => {
// Remove comments, newlines and multiple spaces
const escapedSql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '').replace(/\s\s+/g, ' ');
if (process.type !== undefined) {
const mainWindow = require('electron').webContents.fromId(1);
mainWindow.send('query-log', { cUid, sql: escapedSql, date: new Date() });
}
if (process.env.NODE_ENV === 'development') console.log(escapedSql);
};
/**
* As Simple As Possible Query Builder Core
*/
export abstract class AntaresCore {
_client: antares.ClientCode;
protected _cUid: string
protected _params: mysql.ConnectionOptions | pg.ClientConfig | { databasePath: string; readonly: boolean};
protected _poolSize: number;
protected _ssh?: SSH2Promise;
protected _logger: (args: {sql: string; cUid: string}) => void;
protected _queryDefaults: antares.QueryBuilderObject;
protected _query: antares.QueryBuilderObject;
constructor (args: antares.ClientParams) {
this._client = args.client;
this._cUid = args.uid;
this._params = args.params;
this._poolSize = args.poolSize || undefined;
this._logger = args.logger || queryLogger;
this._queryDefaults = {
schema: '',
select: [],
from: '',
where: [],
groupBy: [],
orderBy: [],
limit: null,
offset: null,
join: [],
update: [],
insert: [],
delete: false
};
this._query = Object.assign({}, this._queryDefaults);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected _reducer (acc: string[], curr: any) {
const type = typeof curr;
switch (type) {
case 'number':
case 'string':
return [...acc, curr];
case 'object':
if (Array.isArray(curr))
return [...acc, ...curr];
else {
const clausoles = [];
for (const key in curr)
clausoles.push(`${key} ${curr[key]}`);
return clausoles;
}
}
}
private _resetQuery () {
this._query = Object.assign({}, this._queryDefaults);
}
schema (schema: string) {
this._query.schema = schema;
return this;
}
select (...args: string[]) {
this._query.select = [...this._query.select, ...args];
return this;
}
from (table: string) {
this._query.from = table;
return this;
}
into (table: string) {
this._query.from = table;
return this;
}
delete (table: string) {
this._query.delete = true;
this.from(table);
return this;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
where (...args: any) {
this._query.where = [...this._query.where, ...args];
return this;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
groupBy (...args: any) {
this._query.groupBy = [...this._query.groupBy, ...args];
return this;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
orderBy (...args: any) {
this._query.orderBy = [...this._query.orderBy, ...args];
return this;
}
limit (limit: number) {
this._query.limit = limit;
return this;
}
offset (offset: number) {
this._query.offset = offset;
return this;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
update (...args: any) {
this._query.update = [...this._query.update, ...args];
return this;
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
insert (arr: {[key: string]: any}[]) {
this._query.insert = [...this._query.insert, ...arr];
return this;
}
getSQL (): string {
throw new Error('Client must implement the "getSQL" method');
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
raw<T = antares.QueryResult> (_sql: string, _args?: antares.QueryParams): Promise<T> {
throw new Error('Client must implement the "raw" method');
}
run<RowType> (args?: antares.QueryParams) {
const rawQuery = this.getSQL();
this._resetQuery();
return this.raw<antares.QueryResult<RowType>>(rawQuery, args);
}
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-explicit-any */
getDbConfig () {
throw new Error('Method "getDbConfig" not implemented');
}
createSchema (...args: any) {
throw new Error('Method "createSchema" not implemented');
}
alterSchema (...args: any) {
throw new Error('Method "alterSchema" not implemented');
}
dropSchema (...args: any) {
throw new Error('Method "dropSchema" not implemented');
}
getDatabaseCollation (...args: any) {
throw new Error('Method "getDatabaseCollation" not implemented');
}
getFunctionInformations (...args: any) {
throw new Error('Method "getFunctionInformations" not implemented');
}
alterFunction (...args: any) {
throw new Error('Method "alterFunction" not implemented');
}
createTriggerFunction (...args: any) {
throw new Error('Method "createTriggerFunction" not implemented');
}
alterTriggerFunction (...args: any) {
throw new Error('Method "alterTriggerFunction" not implemented');
}
createFunction (...args: any) {
throw new Error('Method "createFunction" not implemented');
}
dropFunction (...args: any) {
throw new Error('Method "dropFunction" not implemented');
}
getCollations () {
throw new Error('Method "getCollations" not implemented');
}
getRoutineInformations (...args: any) {
throw new Error('Method "getRoutineInformations" not implemented');
}
dropRoutine (...args: any) {
throw new Error('Method "dropRoutine" not implemented');
}
alterRoutine (...args: any) {
throw new Error('Method "alterRoutine" not implemented');
}
createRoutine (...args: any) {
throw new Error('Method "createRoutine" not implemented');
}
getVariables () {
throw new Error('Method "getVariables" not implemented');
}
getEventInformations (...args: any) {
throw new Error('Method "getEventInformations" not implemented');
}
dropEvent (...args: any) {
throw new Error('Method "dropEvent" not implemented');
}
alterEvent (...args: any) {
throw new Error('Method "alterEvent" not implemented');
}
createEvent (...args: any) {
throw new Error('Method "createEvent" not implemented');
}
enableEvent (...args: any) {
throw new Error('Method "enableEvent" not implemented');
}
disableEvent (...args: any) {
throw new Error('Method "disableEvent" not implemented');
}
enableTrigger (...args: any) {
throw new Error('Method "enableTrigger" not implemented');
}
disableTrigger (...args: any) {
throw new Error('Method "disableTrigger" not implemented');
}
killTabQuery (...args: any) {
throw new Error('Method "killTabQuery" not implemented');
}
/* eslint-enable @typescript-eslint/no-unused-vars */
/* eslint-enable @typescript-eslint/no-explicit-any */
}

View File

@@ -1,47 +0,0 @@
'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
const escapedSql = sql.replace(/(\/\*(.|[\r\n])*?\*\/)|(--(.*|[\r\n]))/gm, '').replace(/\s\s+/g, ' ');
console.log(escapedSql);
};
export class ClientsFactory {
/**
* Returns a database connection based on received args.
*
* @param {Object} args
* @param {String} args.client
* @param {Object} args.params
* @param {String} args.params.host
* @param {Number} args.params.port
* @param {String} args.params.password
* @param {String=} args.params.database
* @param {String=} args.params.schema
* @param {String} args.params.ssh.host
* @param {String} args.params.ssh.username
* @param {String} args.params.ssh.password
* @param {Number} args.params.ssh.port
* @param {Number=} args.poolSize
* @returns Database Connection
* @memberof ClientsFactory
*/
static getConnection (args) {
args.logger = queryLogger;
switch (args.client) {
case 'mysql':
case 'maria':
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}`);
}
}
}

View File

@@ -0,0 +1,23 @@
import * as antares from 'common/interfaces/antares';
import { MySQLClient } from './clients/MySQLClient';
import { PostgreSQLClient } from './clients/PostgreSQLClient';
import { SQLiteClient } from './clients/SQLiteClient';
import { FirebirdSQLClient } from './clients/FirebirdSQLClient';
export class ClientsFactory {
static getClient (args: antares.ClientParams) {
switch (args.client) {
case 'mysql':
case 'maria':
return new MySQLClient(args);
case 'pg':
return new PostgreSQLClient(args);
case 'sqlite':
return new SQLiteClient(args);
case 'firebird':
return new FirebirdSQLClient(args);
default:
throw new Error(`Unknown database client: ${args.client}`);
}
}
}

View File

@@ -0,0 +1,139 @@
import { BrowserWindow, globalShortcut, Menu, MenuItem, MenuItemConstructorOptions } from 'electron';
import * as Store from 'electron-store';
import { ShortcutRecord, shortcuts } from 'common/shortcuts';
const shortcutsStore = new Store({ name: 'shortcuts' });
const isDevelopment = process.env.NODE_ENV !== 'production';
const defaultShortcuts = shortcuts.filter(s => s.os.includes(process.platform));
export type ShortcutMode = 'local' | 'global'
export type OsMenu = {
[key in NodeJS.Platform]?: MenuItemConstructorOptions[];
};
export class ShortcutRegister {
private _shortcuts: ShortcutRecord[];
private _mainWindow: BrowserWindow;
private _menu: Menu;
private _menuTemplate: OsMenu;
private _mode: ShortcutMode;
private static _instance: ShortcutRegister;
private constructor (args: { mainWindow: BrowserWindow; menuTemplate?: OsMenu; mode: ShortcutMode }) {
this._mainWindow = args.mainWindow;
this._menuTemplate = args.menuTemplate || {};
this._mode = args.mode;
this.shortcuts = shortcutsStore.get('shortcuts', defaultShortcuts) as ShortcutRecord[];
}
public static getInstance (args?: { mainWindow?: BrowserWindow; menuTemplate?: OsMenu; mode?: ShortcutMode }) {
if (!ShortcutRegister._instance && args.menuTemplate !== undefined && args.mode !== undefined) {
ShortcutRegister._instance = new ShortcutRegister({
mainWindow: args.mainWindow,
menuTemplate: args.menuTemplate,
mode: args.mode
});
}
return ShortcutRegister._instance;
}
get shortcuts () {
return this._shortcuts;
}
private set shortcuts (value: ShortcutRecord[]) {
this._shortcuts = value;
shortcutsStore.set('shortcuts', value);
}
init () {
this._mainWindow.webContents.send('update-shortcuts', this.shortcuts);
this.buildBaseMenu();
if (this._mode === 'global')
this.setGlobalShortcuts();
else if (this._mode === 'local')
this.setLocalShortcuts();
else
throw new Error(`Unknown mode "${this._mode}"`);
Menu.setApplicationMenu(this._menu);
}
private buildBaseMenu () {
if (Object.keys(this._menuTemplate).includes(process.platform))
this._menu = Menu.buildFromTemplate(this._menuTemplate[process.platform]);
else
this._menu = new Menu();
}
private setLocalShortcuts () {
for (const shortcut of this.shortcuts) {
if (shortcut.os.includes(process.platform)) {
for (const key of shortcut.keys) {
try {
this._menu.append(new MenuItem({
label: 'Shortcuts',
visible: false,
submenu: [{
label: String(key),
accelerator: key,
visible: false,
click: () => {
this._mainWindow.webContents.send(shortcut.event);
if (isDevelopment) console.log('LOCAL EVENT:', shortcut);
}
}]
}));
}
catch (error) {
if (isDevelopment) console.log(error);
this.restoreDefaults();
throw error;
}
}
}
}
}
private setGlobalShortcuts () {
for (const shortcut of this.shortcuts) {
if (shortcut.os.includes(process.platform)) {
for (const key of shortcut.keys) {
try {
globalShortcut.register(key, () => {
this._mainWindow.webContents.send(shortcut.event);
if (isDevelopment) console.log('GLOBAL EVENT:', shortcut);
});
}
catch (error) {
if (isDevelopment) console.log(error);
this.restoreDefaults();
throw error;
}
}
}
}
}
reload () {
this.unregister();
this.init();
}
updateShortcuts (shortcuts: ShortcutRecord[]) {
this.shortcuts = shortcuts;
this.reload();
}
restoreDefaults () {
this.shortcuts = defaultShortcuts;
this.reload();
}
unregister () {
if (this._mode === 'global') globalShortcut.unregisterAll();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,66 +1,77 @@
'use strict';
import sqlite from 'better-sqlite3';
import * as antares from 'common/interfaces/antares';
import * as sqlite from 'better-sqlite3';
import { AntaresCore } from '../AntaresCore';
import dataTypes from 'common/data-types/mysql';
import dataTypes from 'common/data-types/sqlite';
import { NUMBER, FLOAT, TIME, DATETIME } from 'common/fieldTypes';
export class SQLiteClient extends AntaresCore {
constructor (args) {
private _schema?: string;
private _connectionsToCommit: Map<string, sqlite.Database>;
protected _connection?: sqlite.Database;
_params: { databasePath: string; readonly: boolean};
constructor (args: antares.ClientParams) {
super(args);
this._schema = null;
this._connectionsToCommit = new Map();
}
_getTypeInfo (type) {
getTypeInfo (type: string): antares.TypeInformations {
return dataTypes
.reduce((acc, group) => [...acc, ...group.types], [])
.filter(_type => _type.name === type.toUpperCase())[0];
}
/**
* @memberof SQLiteClient
*/
async connect () {
this._connection = sqlite(this._params.databasePath, {
this._connection = this.getConnection();
}
getConnection () {
return sqlite(this._params.databasePath, {
fileMustExist: true,
readonly: this._params.readonly
});
}
/**
* @memberof SQLiteClient
*/
destroy () {}
destroy (): void {
return null;
}
/**
* Executes an USE query
*
* @memberof SQLiteClient
*/
use () {}
use (): void {
return null;
}
/**
* @param {Array} schemas list
* @returns {Array.<Object>} databases scructure
* @memberof SQLiteClient
*/
async getStructure (schemas) {
const { rows: databases } = await this.raw('SELECT * FROM pragma_database_list');
async getStructure (schemas: Set<string>) {
/* eslint-disable camelcase */
interface ShowTableResult {
Db?: string;
type: string;
name: string;
tbl_name: string;
rootpage:4;
sql: string;
}
type ShowTriggersResult = ShowTableResult
/* eslint-enable camelcase */
const { rows: databases } = await this.raw<antares.QueryResult<{ name: string}>>('SELECT * FROM pragma_database_list');
const filteredDatabases = databases;
const tablesArr = [];
const triggersArr = [];
const tablesArr: ShowTableResult[] = [];
const triggersArr: ShowTriggersResult[] = [];
let schemaSize = 0;
for (const db of filteredDatabases) {
if (!schemas.has(db.name)) continue;
let { rows: tables } = await this.raw(`
let { rows: tables } = await this.raw<antares.QueryResult<ShowTableResult>>(`
SELECT *
FROM "${db.name}".sqlite_master
WHERE type IN ('table', 'view')
AND name NOT LIKE 'sqlite_%'
AND name NOT LIKE 'sqlite\\_%' ESCAPE '\\'
ORDER BY name
`);
if (tables.length) {
@@ -71,7 +82,7 @@ export class SQLiteClient extends AntaresCore {
tablesArr.push(...tables);
}
let { rows: triggers } = await this.raw(`SELECT * FROM "${db.name}".sqlite_master WHERE type='trigger'`);
let { rows: triggers } = await this.raw<antares.QueryResult<ShowTriggersResult>>(`SELECT * FROM "${db.name}".sqlite_master WHERE type='trigger'`);
if (triggers.length) {
triggers = triggers.map(trigger => {
trigger.Db = db.name;
@@ -128,22 +139,24 @@ export class SQLiteClient extends AntaresCore {
});
}
/**
* @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}')`);
async getTableColumns ({ schema, table }: { schema: string; table: string }) {
interface TableColumnsResult {
cid: number;
name: string;
type: string;
notnull: 0 | 1;
// eslint-disable-next-line camelcase
dflt_value: string;
pk: 0 | 1;
}
const { rows: fields } = await this.raw<antares.QueryResult<TableColumnsResult>>(`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;
const [type, length]: [string, number?] = field.type.includes('(')
? field.type.replace(')', '').split('(').map((el: string | number) => {
if (!isNaN(Number(el))) el = Number(el);
return el;
})
}) as [string, number?]
: [field.type, null];
return {
@@ -158,7 +171,7 @@ export class SQLiteClient extends AntaresCore {
nullable: !field.notnull,
unsigned: null,
zerofill: null,
order: field.cid + 1,
order: typeof field.cid === 'string' ? +field.cid + 1 : field.cid + 1,
default: field.dflt_value,
charset: null,
collation: null,
@@ -169,54 +182,46 @@ export class SQLiteClient extends AntaresCore {
});
}
/**
* @param {Object} params
* @param {String} params.schema
* @param {String} params.table
* @returns {Object} table row count
* @memberof SQLiteClient
*/
async getTableApproximateCount ({ schema, table }) {
async getTableApproximateCount ({ schema, table }: { schema: string; table: string }): Promise<number> {
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 }) {
async getTableOptions ({ table }: { table: string }) {
return { name: table };
}
/**
* @param {Object} params
* @param {String} params.schema
* @param {String} params.table
* @returns {Object} table indexes
* @memberof SQLiteClient
*/
async getTableIndexes ({ schema, table }) {
async getTableIndexes ({ schema, table }: { schema: string; table: string }) {
interface TableColumnsResult {
type: string;
name: string;
// eslint-disable-next-line camelcase
tbl_name: string;
rootpage:4;
sql: string;
}
interface ShowIndexesResult {
seq: number;
name: string;
unique: 0 | 1;
origin: string;
partial: 0 | 1;
}
const remappedIndexes = [];
const { rows: primaryKeys } = await this.raw(`SELECT * FROM "${schema}".pragma_table_info('${table}') WHERE pk != 0`);
const { rows: primaryKeys } = await this.raw<antares.QueryResult<TableColumnsResult>>(`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: ''
type: 'PRIMARY'
});
}
const { rows: indexes } = await this.raw(`SELECT * FROM "${schema}".pragma_index_list('${table}');`);
const { rows: indexes } = await this.raw<antares.QueryResult<ShowIndexesResult>>(`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}');`);
@@ -225,9 +230,9 @@ export class SQLiteClient extends AntaresCore {
remappedIndexes.push({
name: index.name,
column: detail.name,
indexType: null,
indexType: null as never,
type: index.unique === 1 ? 'UNIQUE' : 'INDEX',
cardinality: null,
cardinality: null as never,
comment: '',
indexComment: ''
});
@@ -237,15 +242,19 @@ export class SQLiteClient extends AntaresCore {
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}');`);
async getKeyUsage ({ schema, table }: { schema: string; table: string }) {
/* eslint-disable camelcase */
interface KeyResult {
from: string;
id: number;
table: string;
to: string;
on_update: string;
on_delete: string;
}
/* eslint-enable camelcase */
const { rows } = await this.raw<antares.QueryResult<KeyResult>>(`SELECT * FROM "${schema}".pragma_foreign_key_list('${table}');`);
return rows.map(field => {
return {
@@ -264,195 +273,11 @@ export class SQLiteClient extends AntaresCore {
});
}
async getUsers () {}
/**
* SHOW CREATE VIEW
*
* @returns {Array.<Object>} 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];
async getUsers (): Promise<void> {
return null;
}
/**
* DROP VIEW
*
* @returns {Array.<Object>} parameters
* @memberof SQLiteClient
*/
async dropView (params) {
const sql = `DROP VIEW "${params.schema}"."${params.view}"`;
return await this.raw(sql);
}
/**
* ALTER VIEW
*
* @returns {Array.<Object>} 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.<Object>} 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.<Object>} 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.<Object>} parameters
* @memberof SQLiteClient
*/
async dropTrigger (params) {
const sql = `DROP TRIGGER \`${params.schema}\`.\`${params.trigger}\``;
return await this.raw(sql);
}
/**
* ALTER TRIGGER
*
* @returns {Array.<Object>} 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.<Object>} 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.<Object>} collations list
* @memberof SQLiteClient
*/
async getCollations () {
return [];
}
/**
* SHOW VARIABLES
*
* @returns {Array.<Object>} variables list
* @memberof SQLiteClient
*/
async getVariables () {
return [];
}
/**
* SHOW ENGINES
*
* @returns {Array.<Object>} engines list
* @memberof SQLiteClient
*/
async getEngines () {
return {
name: 'SQLite',
support: 'YES',
comment: '',
isDefault: true
};
}
/**
* SHOW VARIABLES LIKE '%vers%'
*
* @returns {Array.<Object>} 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 () {}
/**
* CREATE TABLE
*
* @returns {Promise<null>}
* @memberof SQLiteClient
*/
async createTable (params) {
async createTable (params: antares.CreateTableParams) {
const {
schema,
fields,
@@ -460,24 +285,24 @@ export class SQLiteClient extends AntaresCore {
indexes,
options
} = params;
const newColumns = [];
const newIndexes = [];
const manageIndexes = [];
const newForeigns = [];
const newColumns: string[] = [];
const newIndexes: string[] = [];
const manageIndexes: string[] = [];
const newForeigns: string[] = [];
let sql = `CREATE TABLE "${schema}"."${options.name}"`;
// ADD FIELDS
fields.forEach(field => {
const typeInfo = this._getTypeInfo(field.type);
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.type.toUpperCase()}${length ? `(${length})` : ''}
${field.unsigned ? 'UNSIGNED' : ''}
${field.nullable ? 'NULL' : 'NOT NULL'}
${field.autoIncrement ? 'AUTO_INCREMENT' : ''}
${field.default ? `DEFAULT ${field.default}` : ''}
${field.default !== null ? `DEFAULT ${field.default || '\'\''}` : ''}
${field.onUpdate ? `ON UPDATE ${field.onUpdate}` : ''}`);
});
@@ -503,34 +328,51 @@ export class SQLiteClient extends AntaresCore {
return await this.raw(sql);
}
/**
* ALTER TABLE
*
* @returns {Promise<null>}
* @memberof SQLiteClient
*/
async alterTable (params) {
async alterTable (params: antares.AlterTableParams) {
const {
table,
schema,
additions,
deletions,
changes,
tableStructure
} = 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}"`);
const tmpName = `Antares_${table}_tmp`;
await this.raw(`CREATE TABLE "${tmpName}" AS SELECT * FROM "${table}"`);
// Get table triggers before drop
const { rows: triggers } = await this.raw(`SELECT * FROM "${schema}".sqlite_master WHERE type='trigger' AND tbl_name = '${table}'`);
const remappedTriggers = triggers.map((row) => {
return {
schema,
sql: row.sql.match(/(BEGIN|begin)(.*)(END|end)/gs)[0],
name: row.name,
table: row.sql.match(/(?<=ON `).*?(?=`)/gs)[0],
activation: row.sql.match(/(BEFORE|AFTER)/gs)[0],
event: row.sql.match(/(INSERT|UPDATE|DELETE)/gs)[0]
};
});
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 }
schema: schema,
fields: tableStructure.fields,
foreigns: tableStructure.foreigns,
indexes: tableStructure.indexes.filter(index => !index.name.includes('sqlite_autoindex')),
options: { name: 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)
additions.every(add => add.name !== field.name) &&
deletions.every(del => del.name !== field.name)
);
})
.reduce((acc, curr) => {
@@ -539,7 +381,7 @@ export class SQLiteClient extends AntaresCore {
}, []);
const selectFields = insertFields.map(field => {
const renamedField = params.changes.find(change => `"${change.name}"` === field);
const renamedField = changes.find(change => `"${change.name}"` === field);
if (renamedField)
return `"${renamedField.orgName}"`;
return field;
@@ -547,7 +389,12 @@ export class SQLiteClient extends AntaresCore {
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.dropTable({ schema: schema, table: tmpName });
// Recreates triggers
for (const trigger of remappedTriggers)
await this.createTrigger(trigger);
await this.raw('PRAGMA foreign_keys = 1');
await this.raw('COMMIT');
}
@@ -557,43 +404,147 @@ export class SQLiteClient extends AntaresCore {
}
}
/**
* DUPLICATE TABLE
*
* @returns {Promise<null>}
* @memberof SQLiteClient
*/
async duplicateTable (params) { // TODO: retrive table informations and create a copy
async duplicateTable (params: { schema: string; table: string }) { // 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<null>}
* @memberof SQLiteClient
*/
async truncateTable (params) {
async truncateTable (params: { schema: string; table: string }) {
const sql = `DELETE FROM "${params.schema}"."${params.table}"`;
return await this.raw(sql);
}
/**
* DROP TABLE
*
* @returns {Promise<null>}
* @memberof SQLiteClient
*/
async dropTable (params) {
async dropTable (params: { schema: string; table: string }) {
const sql = `DROP TABLE "${params.schema}"."${params.table}"`;
return await this.raw(sql);
}
/**
* @returns {String} SQL string
* @memberof SQLiteClient
*/
async getViewInformations ({ schema, view }: { schema: string; view: string }) {
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];
}
async dropView (params: { schema: string; view: string }) {
const sql = `DROP VIEW "${params.schema}"."${params.view}"`;
return await this.raw(sql);
}
async alterView ({ view }: { view: antares.AlterViewParams }) {
try {
await this.dropView({ schema: view.schema, view: view.oldName });
await this.createView(view);
}
catch (err) {
return Promise.reject(err);
}
}
async createView (params: antares.CreateViewParams) {
const sql = `CREATE VIEW "${params.schema}"."${params.name}" AS ${params.sql}`;
return await this.raw(sql);
}
async getTriggerInformations ({ schema, trigger }: { schema: string; trigger: string }) {
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];
}
async dropTrigger (params: { schema: string; trigger: string }) {
const sql = `DROP TRIGGER \`${params.schema}\`.\`${params.trigger}\``;
return await this.raw(sql);
}
async alterTrigger ({ trigger } : {trigger: antares.AlterTriggerParams}) {
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);
}
}
async createTrigger (params: antares.CreateTriggerParams) {
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 });
}
async getEngines () {
return {
name: 'SQLite',
support: 'YES',
comment: '',
isDefault: true
};
}
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 (): Promise<void> {
return null;
}
async killProcess (): Promise<void> {
return null;
}
async commitTab (tabUid: string) {
const connection = this._connectionsToCommit.get(tabUid);
if (connection) {
connection.prepare('COMMIT').run();
return this.destroyConnectionToCommit(tabUid);
}
}
async rollbackTab (tabUid: string) {
const connection = this._connectionsToCommit.get(tabUid);
if (connection) {
connection.prepare('ROLLBACK').run();
return this.destroyConnectionToCommit(tabUid);
}
}
destroyConnectionToCommit (tabUid: string) {
const connection = this._connectionsToCommit.get(tabUid);
if (connection) {
connection.close();
this._connectionsToCommit.delete(tabUid);
}
}
getSQL () {
// SELECT
const selectArray = this._query.select.reduce(this._reducer, []);
@@ -641,31 +592,23 @@ export class SQLiteClient extends AntaresCore {
const orderByRaw = orderByArray.length ? `ORDER BY ${orderByArray.join(', ')} ` : '';
// LIMIT
const limitRaw = this._query.limit.length ? `LIMIT ${this._query.limit.join(', ')} ` : '';
const limitRaw = this._query.limit ? `LIMIT ${this._query.limit} ` : '';
// OFFSET
const offsetRaw = this._query.offset.length ? `OFFSET ${this._query.offset.join(', ')} ` : '';
const offsetRaw = this._query.offset ? `OFFSET ${this._query.offset} ` : '';
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
async raw<T = antares.QueryResult> (sql: string, args?: antares.QueryParams) {
this._logger({ cUid: this._cUid, sql });// TODO: replace BLOB content with a placeholder
args = {
nest: false,
details: false,
split: true,
comments: true,
autocommit: true,
...args
};
@@ -679,37 +622,53 @@ export class SQLiteClient extends AntaresCore {
.filter(Boolean)
.map(q => q.trim())
: [sql];
const connection = this._connection;
let connection: sqlite.Database;
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 keysArr: antares.QueryForeign[] = [];
const { rows, report, fields, keys, duration } = await new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const { rows, report, fields, keys, duration }: any = await new Promise((resolve, reject) => {
(async () => {
let queryResult;
let queryRunResult: sqlite.RunResult;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let queryAllResult: any[];
let affectedRows;
let fields;
const detectedTypes = {};
const detectedTypes: {[key: string]: string} = {};
try {
const stmt = connection.prepare(query);
if (stmt.reader) {
queryResult = stmt.all();
queryAllResult = stmt.all();
fields = stmt.columns();
if (queryResult.length) {
if (queryAllResult.length) {
fields.forEach(field => {
detectedTypes[field.name] = typeof queryResult[0][field.name];
detectedTypes[field.name] = typeof queryAllResult[0][field.name];
});
}
}
else {
const info = queryResult = stmt.run();
affectedRows = info.changes;
queryRunResult = stmt.run();
affectedRows = queryRunResult.changes;
}
}
catch (err) {
@@ -720,20 +679,20 @@ export class SQLiteClient extends AntaresCore {
let remappedFields = fields
? fields.map(field => {
let [parsedType, length] = field.type?.includes('(')
? field.type.replace(')', '').split('(').map(el => {
if (!isNaN(el))
el = +el;
let [parsedType, length]: [string, number?] = field.type?.includes('(')
? field.type.replace(')', '').split('(').map((el: string | number) => {
if (!isNaN(Number(el)))
el = Number(el);
else
el = el.trim();
el = (el as string).trim();
return el;
})
}) as [string, number?]
: [field.type, null];
if ([...TIME, ...DATETIME].includes(parsedType)) {
const firstNotNull = queryResult.find(res => res[field.name] !== null);
if (firstNotNull[field.name].includes('.'))
length = firstNotNull[field.name].split('.').pop().length;
const firstNotNull = queryAllResult.find(res => res[field.name] !== null);
if (firstNotNull && String(firstNotNull[field.name]).includes('.'))
length = String(firstNotNull[field.name]).split('.').pop().length;
}
return {
@@ -745,7 +704,8 @@ export class SQLiteClient extends AntaresCore {
tableAlias: field.table,
orgTable: field.table,
type: field.type !== null ? parsedType : detectedTypes[field.name],
length
length,
key: undefined as string
};
}).filter(Boolean)
: [];
@@ -765,18 +725,12 @@ export class SQLiteClient extends AntaresCore {
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;
@@ -789,8 +743,8 @@ export class SQLiteClient extends AntaresCore {
}
resolve({
duration: timeStop - timeStart,
rows: Array.isArray(queryResult) ? queryResult.some(el => Array.isArray(el)) ? [] : queryResult : false,
duration: timeStop.getTime() - timeStart.getTime(),
rows: Array.isArray(queryAllResult) ? queryAllResult.some(el => Array.isArray(el)) ? [] : queryAllResult : false,
report: affectedRows !== undefined ? { affectedRows } : null,
fields: remappedFields,
keys: keysArr
@@ -801,6 +755,16 @@ export class SQLiteClient extends AntaresCore {
resultsArr.push({ rows, report, fields, keys, duration });
}
return resultsArr.length === 1 ? resultsArr[0] : resultsArr;
const result = resultsArr.length === 1 ? resultsArr[0] : resultsArr;
return result as unknown as T;
}
getVariables (): null[] {
return [];
}
getCollations (): null[] {
return [];
}
}

View File

@@ -0,0 +1,93 @@
import * as exporter from 'common/interfaces/exporter';
import * as fs from 'fs';
import { createGzip, Gzip } from 'zlib';
import * as path from 'path';
import * as EventEmitter from 'events';
export class BaseExporter extends EventEmitter {
protected _tables;
protected _options;
protected _isCancelled;
protected _outputFileStream: fs.WriteStream;
protected _processedStream: fs.WriteStream | Gzip;
protected _state;
constructor (tables: exporter.TableParams[], options: exporter.ExportOptions) {
super();
this._tables = tables;
this._options = options;
this._isCancelled = false;
this._outputFileStream = fs.createWriteStream(this._options.outputFile, { flags: 'w' });
this._processedStream = null;
this._state = {};
if (this._options.outputFormat === 'sql.zip') {
const outputZipStream = createGzip();
outputZipStream.pipe(this._outputFileStream);
this._processedStream = outputZipStream;
}
else
this._processedStream = this._outputFileStream;
this._processedStream.once('error', err => {
this._isCancelled = true;
this.emit('error', err);
});
}
async run () {
try {
this.emit('start', this);
await this.dump();
}
catch (err) {
this.emit('error', err);
throw err;
}
finally {
this._processedStream.end();
this.emit('end');
}
}
get isCancelled () {
return this._isCancelled;
}
get outputFile () {
return this._options.outputFile;
}
outputFileExists () {
return fs.existsSync(this._options.outputFile);
}
cancel () {
this._isCancelled = true;
this.emit('cancel');
this.emitUpdate({ op: 'cancelling' });
}
emitUpdate (state: exporter.ExportState) {
this.emit('progress', { ...this._state, ...state });
}
writeString (data: string) {
if (this._isCancelled) return;
try {
fs.accessSync(this._options.outputFile);
}
catch (err) {
this._isCancelled = true;
const fileName = path.basename(this._options.outputFile);
this.emit('error', `The file ${fileName} is not accessible`);
}
this._processedStream.write(data);
}
dump () {
throw new Error('Exporter must implement the "dump" method');
}
}

View File

@@ -0,0 +1,387 @@
import * as exporter from 'common/interfaces/exporter';
import * as mysql from 'mysql2/promise';
import { SqlExporter } from './SqlExporter';
import { MySQLClient } from '../../clients/MySQLClient';
import { valueToSqlString } from 'common/libs/sqlUtils';
export default class MysqlExporter extends SqlExporter {
protected _client: MySQLClient;
constructor (client: MySQLClient, tables: exporter.TableParams[], options: exporter.ExportOptions) {
super(tables, options);
this._client = client;
this._commentChar = '#';
}
async getSqlHeader () {
let dump = await super.getSqlHeader();
dump += `
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
SET NAMES utf8mb4;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;`;
return dump;
}
async getFooter () {
const footer = await super.getFooter();
return `/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
${footer}
`;
}
async getCreateTable (tableName: string) {
const { rows } = await this._client.raw(
`SHOW CREATE TABLE \`${this.schemaName}\`.\`${tableName}\``
);
if (rows.length !== 1) return '';
const col = 'Create View' in rows[0] ? 'Create View' : 'Create Table';
return rows[0][col] + ';';
}
getDropTable (tableName: string) {
return `DROP TABLE IF EXISTS \`${tableName}\`;`;
}
async * getTableInsert (tableName: string) {
let rowCount = 0;
let sqlStr = '';
const countResults = await this._client.raw(`SELECT COUNT(1) as count FROM \`${this.schemaName}\`.\`${tableName}\``);
if (countResults.rows.length === 1) rowCount = countResults.rows[0].count;
if (rowCount > 0) {
let queryLength = 0;
let rowsWritten = 0;
let rowIndex = 0;
const { sqlInsertDivider, sqlInsertAfter } = this._options;
const columns = await this._client.getTableColumns({
table: tableName,
schema: this.schemaName
});
const notGeneratedColumns = columns.filter(col => !col.generated);
const columnNames = notGeneratedColumns.map(col => '`' + col.name + '`');
const insertStmt = `INSERT INTO \`${tableName}\` (${columnNames.join(
', '
)}) VALUES`;
sqlStr += `LOCK TABLES \`${tableName}\` WRITE;\n`;
sqlStr += `/*!40000 ALTER TABLE \`${tableName}\` DISABLE KEYS */;`;
sqlStr += '\n\n';
yield sqlStr;
yield insertStmt;
const stream = await this._queryStream(
`SELECT ${columnNames.join(', ')} FROM \`${this.schemaName}\`.\`${tableName}\``
);
for await (const row of stream) {
if (this.isCancelled) {
stream.destroy();
yield null;
return;
}
let sqlInsertString = '';
if (
(sqlInsertDivider === 'bytes' && queryLength >= sqlInsertAfter * 1024) ||
(sqlInsertDivider === 'rows' && rowsWritten === sqlInsertAfter)
) {
sqlInsertString += `;\n${insertStmt}\n\t(`;
queryLength = 0;
rowsWritten = 0;
}
else if (rowIndex === 0) sqlInsertString += '\n\t(';
else sqlInsertString += ',\n\t(';
for (const i in notGeneratedColumns) {
const column = notGeneratedColumns[i];
const val = row[column.name];
sqlInsertString += valueToSqlString({ val, client: 'mysql', field: column });
if (parseInt(i) !== notGeneratedColumns.length - 1)
sqlInsertString += ', ';
}
sqlInsertString += ')';
queryLength += sqlInsertString.length;
rowsWritten++;
rowIndex++;
yield sqlInsertString;
}
sqlStr = ';\n\n';
sqlStr += `/*!40000 ALTER TABLE \`${tableName}\` ENABLE KEYS */;\n`;
sqlStr += 'UNLOCK TABLES;';
yield sqlStr;
}
}
async getViews () {
const { rows: views } = await this._client.raw(
`SHOW TABLE STATUS FROM \`${this.schemaName}\` WHERE Comment = 'VIEW'`
);
let sqlString = '';
sqlString += this.buildComment('Creating temporary tables to overcome VIEW dependency errors');
// Temporary tables
for (const view of views) {
const viewFields = await this._client.getTableColumns({ schema: this.schemaName, table: view.Name });
const tableFields: string[] = [];
for (const field of viewFields) {
const typeInfo = this._client.getTypeInfo(field.type);
const length = typeInfo.length ? field.enumValues || field.numLength || field.charLength || field.datePrecision : false;
tableFields.push(`\`${field.name}\` ${field.type.toUpperCase()}${length ? `(${length}${field.numScale ? `,${field.numScale}` : ''})` : ''} ${field.unsigned ? 'UNSIGNED' : ''} ${field.zerofill ? 'ZEROFILL' : ''} ${field.nullable ? 'NULL' : 'NOT NULL'} ${field.autoIncrement ? 'AUTO_INCREMENT' : ''} ${field.collation ? `COLLATE ${field.collation}` : ''}`);
}
sqlString +=
`
CREATE TABLE \`${view.Name}\`(
${tableFields.join(',\n\t')}
);`;
sqlString += '\n';
}
sqlString += '\n';
for (const view of views) {
sqlString += `DROP TABLE IF EXISTS \`${view.Name}\`;\n`;
const viewSyntax = await this.getCreateTable(view.Name);
sqlString += viewSyntax.replaceAll('`' + this.schemaName + '`.', '');
sqlString += '\n\n';
}
return sqlString;
}
async getTriggers () {
const { rows: triggers } = await this._client.raw(
`SHOW TRIGGERS FROM \`${this.schemaName}\``
);
const generatedTables = this._tables
.filter(t => t.includeStructure)
.map(t => t.table);
let sqlString = '';
for (const trigger of triggers) {
const {
Trigger: name,
Timing: timing,
Event: event,
Table: table,
Statement: statement,
sql_mode: sqlMode
} = trigger;
if (!generatedTables.includes(table)) continue;
const definer = this.getEscapedDefiner(trigger.Definer);
sqlString += '/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;;\n';
sqlString += `/*!50003 SET SQL_MODE="${sqlMode}" */;\n`;
sqlString += 'DELIMITER ;;\n';
sqlString += '/*!50003 CREATE*/ ';
sqlString += `/*!50017 DEFINER=${definer}*/ `;
sqlString += `/*!50003 TRIGGER \`${name}\` ${timing} ${event} ON \`${table}\` FOR EACH ROW ${statement}*/;;\n`;
sqlString += 'DELIMITER ;\n';
sqlString += '/*!50003 SET SQL_MODE=@OLD_SQL_MODE */;\n\n';
}
return sqlString;
}
async getSchedulers () {
const { rows: schedulers } = await this._client.raw(
`SELECT *, EVENT_SCHEMA AS \`Db\`, EVENT_NAME AS \`Name\` FROM information_schema.\`EVENTS\` WHERE EVENT_SCHEMA = '${this.schemaName}'`
);
let sqlString = '';
for (const scheduler of schedulers) {
const {
EVENT_NAME: name,
SQL_MODE: sqlMode,
EVENT_TYPE: type,
INTERVAL_VALUE: intervalValue,
INTERVAL_FIELD: intervalField,
STARTS: starts,
ENDS: ends,
EXECUTE_AT: at,
ON_COMPLETION: onCompletion,
STATUS: status,
EVENT_DEFINITION: definition
} = scheduler;
const definer = this.getEscapedDefiner(scheduler.DEFINER);
const comment = this.escapeAndQuote(scheduler.EVENT_COMMENT);
sqlString += `/*!50106 DROP EVENT IF EXISTS \`${name}\` */;\n`;
sqlString += '/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;;\n';
sqlString += `/*!50003 SET SQL_MODE='${sqlMode}' */;\n`;
sqlString += 'DELIMITER ;;\n';
sqlString += '/*!50106 CREATE*/ ';
sqlString += `/*!50117 DEFINER=${definer}*/ `;
sqlString += `/*!50106 EVENT \`${name}\` ON SCHEDULE `;
if (type === 'RECURRING') {
sqlString += `EVERY ${intervalValue} ${intervalField} STARTS '${starts}' `;
if (ends) sqlString += `ENDS '${ends}' `;
}
else sqlString += `AT '${at}' `;
sqlString += `ON COMPLETION ${onCompletion} ${
status === 'disabled' ? 'DISABLE' : 'ENABLE'
} COMMENT ${comment || '\'\''} DO ${definition}*/;;\n`;
sqlString += 'DELIMITER ;\n';
sqlString += '/*!50003 SET SQL_MODE=@OLD_SQL_MODE*/;;\n';
}
return sqlString;
}
async getFunctions () {
const { rows: functions } = await this._client.raw(
`SHOW FUNCTION STATUS WHERE \`Db\` = '${this.schemaName}';`
);
let sqlString = '';
for (const func of functions) {
const definer = this.getEscapedDefiner(func.Definer);
sqlString += await this.getRoutineSyntax(
func.Name,
func.Type,
definer
);
}
return sqlString;
}
async getRoutines () {
const { rows: routines } = await this._client.raw(
`SHOW PROCEDURE STATUS WHERE \`Db\` = '${this.schemaName}';`
);
let sqlString = '';
for (const routine of routines) {
const definer = this.getEscapedDefiner(routine.Definer);
sqlString += await this.getRoutineSyntax(
routine.Name,
routine.Type,
definer
);
}
return sqlString;
}
async getRoutineSyntax (name: string, type: string, definer: string) {
const { rows: routines } = await this._client.raw(
`SHOW CREATE ${type} \`${this.schemaName}\`.\`${name}\``
);
if (routines.length === 0) return '';
const routine = routines[0];
const fieldName = `Create ${type === 'PROCEDURE' ? 'Procedure' : 'Function'}`;
const sqlMode = routine.sql_mode;
const createProcedure = routine[fieldName];
let sqlString = '';
if (createProcedure) { // If procedure body not empty
const startOffset = createProcedure.indexOf(type);
const procedureBody = createProcedure.substring(startOffset);
sqlString += `/*!50003 DROP ${type} IF EXISTS ${name}*/;;\n`;
sqlString += '/*!50003 SET @OLD_SQL_MODE=@@SQL_MODE*/;;\n';
sqlString += `/*!50003 SET SQL_MODE="${sqlMode}"*/;;\n`;
sqlString += 'DELIMITER ;;\n';
sqlString += `/*!50003 CREATE*/ /*!50020 DEFINER=${definer}*/ /*!50003 ${procedureBody}*/;;\n`;
sqlString += 'DELIMITER ;\n';
sqlString += '/*!50003 SET SQL_MODE=@OLD_SQL_MODE*/;\n';
}
return sqlString;
}
async _queryStream (sql: string) {
if (process.env.NODE_ENV === 'development') console.log('EXPORTER:', sql);
const isPool = 'getConnection' in this._client._connection;
const connection = isPool ? await (this._client._connection as mysql.Pool).getConnection() : this._client._connection;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const stream = (connection as any).connection.query(sql).stream();
const dispose = () => (connection as mysql.PoolConnection).release();
stream.on('end', dispose);
stream.on('error', dispose);
stream.on('close', dispose);
return stream;
}
getEscapedDefiner (definer: string) {
return definer
.split('@')
.map(part => '`' + part + '`')
.join('@');
}
escapeAndQuote (val: string) {
// eslint-disable-next-line no-control-regex
const CHARS_TO_ESCAPE = /[\0\b\t\n\r\x1a"'\\]/g;
const CHARS_ESCAPE_MAP: {[key: string]: string} = {
'\0': '\\0',
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\r': '\\r',
'\x1a': '\\Z',
'"': '\\"',
'\'': '\\\'',
'\\': '\\\\'
};
let chunkIndex = CHARS_TO_ESCAPE.lastIndex = 0;
let escapedVal = '';
let match;
while ((match = CHARS_TO_ESCAPE.exec(val))) {
escapedVal += val.slice(chunkIndex, match.index) + CHARS_ESCAPE_MAP[match[0]];
chunkIndex = CHARS_TO_ESCAPE.lastIndex;
}
if (chunkIndex === 0)
return `'${val}'`;
if (chunkIndex < val.length)
return `'${escapedVal + val.slice(chunkIndex)}'`;
return `'${escapedVal}'`;
}
}

View File

@@ -0,0 +1,471 @@
import * as antares from 'common/interfaces/antares';
import * as exporter from 'common/interfaces/exporter';
import { SqlExporter } from './SqlExporter';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import * as QueryStream from 'pg-query-stream';
import { PostgreSQLClient } from '../../clients/PostgreSQLClient';
import { valueToSqlString } from 'common/libs/sqlUtils';
export default class PostgreSQLExporter extends SqlExporter {
constructor (client: PostgreSQLClient, tables: exporter.TableParams[], options: exporter.ExportOptions) {
super(tables, options);
this._client = client;
}
async getSqlHeader () {
let dump = await super.getSqlHeader();
dump += `
SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;\n\n\n`;
if (this.schemaName !== 'public') dump += `CREATE SCHEMA "${this.schemaName}";\n\n`;
dump += await this.getCreateTypes();
return dump;
}
async getCreateTable (tableName: string) {
/* eslint-disable camelcase */
interface SequenceRecord {
sequence_catalog: string;
sequence_schema: string;
sequence_name: string;
data_type: string;
numeric_precision: number;
numeric_precision_radix: number;
numeric_scale: number;
start_value: string;
minimum_value: string;
maximum_value: string;
increment: string;
cycle_option: string;
}
/* eslint-enable camelcase */
let createSql = '';
const sequences = [];
const columnsSql = [];
const arrayTypes: {[key: string]: string} = {
_int2: 'smallint',
_int4: 'integer',
_int8: 'bigint',
_float4: 'real',
_float8: 'double precision',
_char: '"char"',
_varchar: 'character varying'
};
// Table columns
const { rows } = await this._client.raw(`
SELECT *
FROM "information_schema"."columns"
WHERE "table_schema" = '${this.schemaName}'
AND "table_name" = '${tableName}'
ORDER BY "ordinal_position" ASC
`, { schema: 'information_schema' });
if (!rows.length) return '';
for (const column of rows) {
let fieldType = column.data_type;
if (fieldType === 'USER-DEFINED') fieldType = `"${this.schemaName}".${column.udt_name}`;
else if (fieldType === 'ARRAY') {
if (Object.keys(arrayTypes).includes(fieldType))
fieldType = arrayTypes[column.udt_name] + '[]';
else
fieldType = column.udt_name.replaceAll('_', '') + '[]';
}
const columnArr = [
`"${column.column_name}"`,
`${fieldType}${column.character_maximum_length ? `(${column.character_maximum_length})` : ''}`
];
if (column.column_default) {
columnArr.push(`DEFAULT ${column.column_default}`);
if (column.column_default.includes('nextval')) {
const sequenceName = column.column_default.split('\'')[1];
sequences.push(sequenceName);
}
}
if (column.is_nullable === 'NO') columnArr.push('NOT NULL');
columnsSql.push(columnArr.join(' '));
}
// Table sequences
for (let sequence of sequences) {
if (sequence.includes('.')) sequence = sequence.split('.')[1];
const { rows } = await this._client
.select('*')
.schema('information_schema')
.from('sequences')
.where({ sequence_schema: `= '${this.schemaName}'`, sequence_name: `= '${sequence}'` })
.run<SequenceRecord>();
if (rows.length) {
createSql += `CREATE SEQUENCE "${this.schemaName}"."${sequence}"
START WITH ${rows[0].start_value}
INCREMENT BY ${rows[0].increment}
MINVALUE ${rows[0].minimum_value}
MAXVALUE ${rows[0].maximum_value}
CACHE 1;\n`;
// createSql += `\nALTER TABLE "${sequence}" OWNER TO ${this._client._params.user};\n\n`;
}
}
// Table create
createSql += `\nCREATE TABLE "${this.schemaName}"."${tableName}"(
${columnsSql.join(',\n ')}
);\n`;
// createSql += `\nALTER TABLE "${tableName}" OWNER TO ${this._client._params.user};\n\n`;
// Table indexes
createSql += '\n';
const { rows: indexes } = await this._client
.select('*')
.schema('pg_catalog')
.from('pg_indexes')
.where({ schemaname: `= '${this.schemaName}'`, tablename: `= '${tableName}'` })
.run<{indexdef: string}>();
for (const index of indexes)
createSql += `${index.indexdef};\n`;
// Table foreigns
const { rows: foreigns } = await this._client.raw(`
SELECT
tc.table_schema,
tc.constraint_name,
tc.table_name,
kcu.column_name,
ccu.table_schema AS foreign_table_schema,
ccu.table_name AS foreign_table_name,
ccu.column_name AS foreign_column_name,
rc.update_rule,
rc.delete_rule
FROM information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
AND tc.table_schema = kcu.table_schema
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
AND ccu.table_schema = tc.table_schema
JOIN information_schema.referential_constraints AS rc
ON rc.constraint_name = kcu.constraint_name
WHERE tc.constraint_type = 'FOREIGN KEY' AND tc.table_schema = '${this.schemaName}'
AND tc.table_name = '${tableName}'
`);
for (const foreign of foreigns) {
this._postTablesSql += `\nALTER TABLE ONLY "${this.schemaName}"."${tableName}"
ADD CONSTRAINT "${foreign.constraint_name}" FOREIGN KEY ("${foreign.column_name}") REFERENCES "${this.schemaName}"."${foreign.foreign_table_name}" ("${foreign.foreign_column_name}") ON UPDATE ${foreign.update_rule} ON DELETE ${foreign.delete_rule};\n`;
}
return createSql;
}
getDropTable (tableName: string) {
return `DROP TABLE IF EXISTS "${this.schemaName}"."${tableName}";`;
}
async * getTableInsert (tableName: string) {
let rowCount = 0;
const sqlStr = '';
const countResults = await this._client.raw(`SELECT COUNT(1) as count FROM "${this.schemaName}"."${tableName}"`);
if (countResults.rows.length === 1) rowCount = countResults.rows[0].count;
if (rowCount > 0) {
const columns = await this._client.getTableColumns({
table: tableName,
schema: this.schemaName
});
const columnNames = columns.map(col => '"' + col.name + '"').join(', ');
yield sqlStr;
const stream = await this._queryStream(
`SELECT ${columnNames} FROM "${this.schemaName}"."${tableName}"`
);
for await (const row of stream) {
if (this.isCancelled) {
stream.destroy();
yield null;
return;
}
let sqlInsertString = `INSERT INTO "${this.schemaName}"."${tableName}" (${columnNames}) VALUES`;
sqlInsertString += ' (';
for (const i in columns) {
const column = columns[i];
const val = row[column.name];
sqlInsertString += valueToSqlString({ val, client: 'pg', field: column });
if (parseInt(i) !== columns.length - 1)
sqlInsertString += ', ';
}
sqlInsertString += ');\n';
yield sqlInsertString;
}
yield sqlStr;
}
}
async getCreateTypes () {
let sqlString = '';
const { rows: types } = await this._client.raw<antares.QueryResult<{typname: string; enumlabel: string}>>(`
SELECT pg_type.typname, pg_enum.enumlabel
FROM pg_type
JOIN pg_enum ON pg_enum.enumtypid = pg_type.oid;
`);
if (types.length) { // TODO: refactor
sqlString += this.buildComment('Dump of types\n------------------------------------------------------------') + '\n\n';
const typesArr = types.reduce((arr, type) => {
if (arr.every(el => el.name !== type.typname))
arr.push({ name: type.typname, enums: [this.escapeAndQuote(type.enumlabel)] });
else {
const i = arr.findIndex(el => el.name === type.typname);
arr[i].enums.push(this.escapeAndQuote(type.enumlabel));
}
return arr;
}, []);
for (const type of typesArr) {
sqlString += `CREATE TYPE "${this.schemaName}"."${type.name}" AS ENUM (
${type.enums.join(',\n\t')}
);`;
}
// sqlString += `\nALTER TYPE "${tableName}" OWNER TO ${this._client._params.user};\n`
}
return sqlString;
}
async getCreateAggregates () {
let sqlString = '';
const { rows: aggregates } = await this._client.raw(`
SELECT proname
FROM pg_proc
WHERE prokind = 'a'
AND pronamespace::regnamespace::text = '${this.schemaName}'
ORDER BY 1;
`);
if (aggregates.length) {
for (const aggregate of aggregates) {
const { rows: aggregateDef } = await this._client.raw(
`SELECT
format(
E'CREATE AGGREGATE %s (\n%s\n);'
, (pg_identify_object('pg_proc'::regclass, aggfnoid, 0)).identity
, array_to_string(
ARRAY[
format(E'\tSFUNC = %s', aggtransfn::regproc)
, format(E'\tSTYPE = %s', format_type(aggtranstype, NULL))
, CASE aggfinalfn WHEN '-'::regproc THEN NULL ELSE format(E'\tFINALFUNC = %s',aggfinalfn::text) END
, CASE aggsortop WHEN 0 THEN NULL ELSE format(E'\tSORTOP = %s', oprname) END
, CASE WHEN agginitval IS NULL THEN NULL ELSE format(E'\tINITCOND = %s', agginitval) END
]
, E',\n'
)
)
FROM pg_aggregate
LEFT JOIN pg_operator ON pg_operator.oid = aggsortop
WHERE aggfnoid = '${this.schemaName}.${aggregate.proname}'::regproc;`
);
if (aggregateDef.length)
sqlString += '\n\n' + aggregateDef[0].format;
}
}
return sqlString + '\n\n\n';
}
async getViews () {
const { rows: views } = await this._client.raw(`SELECT * FROM "pg_views" WHERE "schemaname"='${this.schemaName}'`);
let sqlString = '';
for (const view of views) {
sqlString += `\nDROP VIEW IF EXISTS "${view.viewname}";\n`;
// const { rows: columns } = await this._client
// .select('*')
// .schema('information_schema')
// .from('columns')
// .where({ table_schema: `= '${this.schemaName}'`, table_name: `= '${view.viewname}'` })
// .orderBy({ ordinal_position: 'ASC' })
// .run();
// sqlString += `
// CREATE VIEW "${this.schemaName}"."${view.viewname}" AS
// SELECT
// ${columns.reduce((acc, curr) => {
// const fieldType = curr.data_type === 'USER-DEFINED' ? curr.udt_name : curr.data_type;
// acc.push(`NULL::${fieldType}${curr.character_maximum_length ? `(${curr.character_maximum_length})` : ''} AS "${curr.column_name}"`);
// return acc;
// }, []).join(',\n ')};
// `;
sqlString += `\nCREATE OR REPLACE VIEW "${this.schemaName}"."${view.viewname}" AS \n${view.definition}\n`;
}
return sqlString;
}
async getTriggers () {
/* eslint-disable camelcase */
interface TriggersResult {
event_object_table: string;
table_name: string;
trigger_name: string;
events: string[];
event_manipulation: string;
}
/* eslint-enable camelcase */
let sqlString = '';
// Trigger functions
const { rows: triggerFunctions } = await this._client.raw(
`SELECT DISTINCT routine_name AS name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND routine_schema = '${this.schemaName}' AND data_type = 'trigger'`
);
for (const func of triggerFunctions) {
const { rows: functionDef } = await this._client.raw(
`SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${func.name}')) AS definition`
);
sqlString += `\n${functionDef[0].definition};\n`;
}
const { rows: triggers } = await this._client.raw<antares.QueryResult<TriggersResult>>(
`SELECT * FROM "information_schema"."triggers" WHERE "trigger_schema"='${this.schemaName}'`
);
const remappedTriggers = triggers.reduce((acc, trigger) => {
const i = acc.findIndex(t => t.trigger_name === trigger.trigger_name && t.event_object_table === trigger.event_object_table);
if (i === -1) {
trigger.events = [trigger.event_manipulation];
acc.push(trigger);
}
else
acc[i].events.push(trigger.event_manipulation);
return acc;
}, []);
for (const trigger of remappedTriggers)
sqlString += `\nCREATE TRIGGER "${trigger.trigger_name}" ${trigger.action_timing} ${trigger.events.join(' OR ')} ON "${this.schemaName}"."${trigger.event_object_table}" FOR EACH ${trigger.action_orientation} ${trigger.action_statement};\n`;
return sqlString;
}
async getFunctions () {
let sqlString = '';
const { rows: functions } = await this._client.raw(
`SELECT DISTINCT routine_name AS name FROM information_schema.routines WHERE routine_type = 'FUNCTION' AND routine_schema = '${this.schemaName}' AND data_type != 'trigger'`
);
for (const func of functions) {
const { rows: functionDef } = await this._client.raw(
`SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${func.name}')) AS definition`
);
sqlString += `\n${functionDef[0].definition};\n`;
}
sqlString += await this.getCreateAggregates();
return sqlString;
}
async getRoutines () {
let sqlString = '';
const { rows: functions } = await this._client.raw(
`SELECT DISTINCT routine_name AS name FROM information_schema.routines WHERE routine_type = 'PROCEDURE' AND routine_schema = '${this.schemaName}'`
);
for (const func of functions) {
const { rows: functionDef } = await this._client.raw(
`SELECT pg_get_functiondef((SELECT oid FROM pg_proc WHERE proname = '${func.name}')) AS definition`
);
sqlString += `\n${functionDef[0].definition};\n`;
}
return sqlString;
}
async _queryStream (sql: string) {
if (process.env.NODE_ENV === 'development') console.log('EXPORTER:', sql);
const connection = await this._client.getConnection();
const query = new QueryStream(sql, null);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const stream = (connection as any).query(query);
const dispose = () => connection.end();
stream.on('end', dispose);
stream.on('error', dispose);
stream.on('close', dispose);
return stream;
}
escapeAndQuote (val: string) {
// eslint-disable-next-line no-control-regex
const CHARS_TO_ESCAPE = /[\0\b\t\n\r\x1a"'\\]/g;
const CHARS_ESCAPE_MAP: {[key: string]: string} = {
'\0': '\\0',
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\r': '\\r',
'\x1a': '\\Z',
'"': '\\"',
'\'': '\\\'',
'\\': '\\\\'
};
let chunkIndex = CHARS_TO_ESCAPE.lastIndex = 0;
let escapedVal = '';
let match;
while ((match = CHARS_TO_ESCAPE.exec(val))) {
escapedVal += val.slice(chunkIndex, match.index) + CHARS_ESCAPE_MAP[match[0]];
chunkIndex = CHARS_TO_ESCAPE.lastIndex;
}
if (chunkIndex === 0)
return `'${val}'`;
if (chunkIndex < val.length)
return `'${escapedVal + val.slice(chunkIndex)}'`;
return `'${escapedVal}'`;
}
}

View File

@@ -0,0 +1,187 @@
import * as moment from 'moment';
import { MySQLClient } from '../../clients/MySQLClient';
import { PostgreSQLClient } from '../../clients/PostgreSQLClient';
import { BaseExporter } from '../BaseExporter';
export class SqlExporter extends BaseExporter {
protected _client: MySQLClient | PostgreSQLClient;
protected _commentChar = '--'
protected _postTablesSql = ''
get schemaName () {
return this._options.schema;
}
get host () {
return this._client._params.host;
}
async getServerVersion () {
const version = await this._client.getVersion();
return `${version.name} ${version.number}`;
}
async dump () {
const { includes } = this._options;
const extraItems = Object.keys(includes).filter((key: 'functions' | 'views' | 'triggers' | 'routines' | 'schedulers') => includes[key]);
const totalTableToProcess = this._tables.filter(
t => t.includeStructure || t.includeContent || t.includeDropStatement
).length;
const processingItemCount = totalTableToProcess + extraItems.length;
const exportState = {
totalItems: processingItemCount,
currentItemIndex: 0,
currentItem: '',
op: ''
};
const header = await this.getSqlHeader();
this.writeString(header);
this.writeString('\n\n\n');
for (const item of this._tables) {
// user abort operation
if (this.isCancelled) return;
// skip item if not set to output any detail for them
if (
!item.includeStructure &&
!item.includeContent &&
!item.includeDropStatement
)
continue;
exportState.currentItemIndex++;
exportState.currentItem = item.table;
exportState.op = 'FETCH';
this.emitUpdate(exportState);
const tableHeader = this.buildComment(
`Dump of table ${item.table}\n------------------------------------------------------------`
);
this.writeString(tableHeader);
this.writeString('\n\n');
if (item.includeDropStatement) {
const dropTableSyntax = this.getDropTable(item.table);
this.writeString(dropTableSyntax);
this.writeString('\n\n');
}
if (item.includeStructure) {
const createTableSyntax = await this.getCreateTable(item.table);
this.writeString(createTableSyntax);
this.writeString('\n\n');
}
if (item.includeContent) {
exportState.op = 'WRITE';
this.emitUpdate(exportState);
for await (const sqlStr of this.getTableInsert(item.table)) {
if (this.isCancelled) return;
this.writeString(sqlStr);
}
this.writeString('\n\n');
}
this.writeString('\n\n');
}
// SQL to execute after tables creation
if (this._postTablesSql) {
this.writeString(this._postTablesSql);
this.writeString('\n\n');
}
for (const item of extraItems) {
type exporterMethods = 'getViews' | 'getTriggers' | 'getSchedulers' | 'getFunctions' | 'getRoutines'
const processingMethod = `get${item.charAt(0).toUpperCase() + item.slice(1)}` as exporterMethods;
exportState.currentItemIndex++;
exportState.currentItem = item;
exportState.op = 'PROCESSING';
this.emitUpdate(exportState);
if (this[processingMethod]) {
const data = await this[processingMethod]() as unknown as string;
if (data !== '') {
const header =
this.buildComment(
`Dump of ${item}\n------------------------------------------------------------`
) + '\n\n';
this.writeString(header);
this.writeString(data);
this.writeString('\n\n');
}
}
}
const footer = await this.getFooter();
this.writeString(footer);
}
buildComment (text: string) {
return text
.split('\n')
.map(txt => `${this._commentChar} ${txt}`)
.join('\n');
}
async getSqlHeader () {
const serverVersion = await this.getServerVersion();
const header = `************************************************************
Antares - SQL Client
Version ${process.env.PACKAGE_VERSION}
https://antares-sql.app/
https://github.com/antares-sql/antares
Host: ${this.host} (${serverVersion})
Database: ${this.schemaName}
Generation time: ${moment().format()}
************************************************************`;
return this.buildComment(header);
}
async getFooter () {
return this.buildComment(`Dump completed on ${moment().format()}`);
}
/* eslint-disable @typescript-eslint/no-unused-vars */
getCreateTable (_tableName: string): Promise<string> {
throw new Error('Sql Exporter must implement the "getCreateTable" method');
}
getDropTable (_tableName: string): string {
throw new Error('Sql Exporter must implement the "getDropTable" method');
}
getTableInsert (_tableName: string): AsyncGenerator<string> {
throw new Error('Sql Exporter must implement the "getTableInsert" method');
}
getViews () {
throw new Error('Method "getViews" not implemented');
}
getTriggers () {
throw new Error('Method "getTriggers" not implemented');
}
getSchedulers () {
throw new Error('Method "getSchedulers" not implemented');
}
getFunctions () {
throw new Error('Method "getFunctions" not implemented');
}
getRoutines () {
throw new Error('Method "getRoutines" not implemented');
}
/* eslint-enable @typescript-eslint/no-unused-vars */
}

View File

@@ -0,0 +1,59 @@
import * as importer from 'common/interfaces/importer';
import * as fs from 'fs';
import * as EventEmitter from 'events';
export class BaseImporter extends EventEmitter {
protected _options;
protected _isCancelled;
protected _fileHandler;
protected _state;
constructor (options: importer.ImportOptions) {
super();
this._options = options;
this._isCancelled = false;
this._fileHandler = fs.createReadStream(this._options.file, {
flags: 'r',
highWaterMark: 4 * 1024
});
this._state = {};
this._fileHandler.once('error', err => {
this._isCancelled = true;
this.emit('error', err);
});
}
async run () {
try {
this.emit('start', this);
await this.import();
}
catch (err) {
this.emit('error', err);
throw err;
}
finally {
this._fileHandler.close();
this.emit('end');
}
}
get isCancelled () {
return this._isCancelled;
}
cancel () {
this._isCancelled = true;
this.emit('cancel');
this.emitUpdate({ op: 'cancelling' });
}
emitUpdate (state: importer.ImportState) {
this.emit('progress', { ...this._state, ...state });
}
import () {
throw new Error('Exporter must implement the "import" method');
}
}

View File

@@ -0,0 +1,85 @@
import * as mysql from 'mysql2';
import * as importer from 'common/interfaces/importer';
import * as fs from 'fs/promises';
import MySQLParser from '../../parsers/MySQLParser';
import { BaseImporter } from '../BaseImporter';
export default class MySQLImporter extends BaseImporter {
protected _client: mysql.Pool
constructor (client: mysql.Pool, options: importer.ImportOptions) {
super(options);
this._client = client;
}
async import (): Promise<void> {
try {
const { size: totalFileSize } = await fs.stat(this._options.file);
const parser = new MySQLParser();
let readPosition = 0;
let queryCount = 0;
this.emitUpdate({
fileSize: totalFileSize,
readPosition: 0,
percentage: 0,
queryCount: 0
});
return new Promise((resolve, reject) => {
this._fileHandler.pipe(parser);
parser.on('error', reject);
parser.on('close', async () => {
console.log('TOTAL QUERIES', queryCount);
console.log('import end');
resolve();
});
parser.on('data', async (query) => {
queryCount++;
parser.pause();
try {
await this._client.query(query);
}
catch (error) {
this.emit('query-error', {
sql: query,
message: error.sqlMessage,
sqlSnippet: error.sql,
time: new Date().getTime()
});
}
this.emitUpdate({
queryCount,
readPosition,
percentage: readPosition / totalFileSize * 100
});
this._fileHandler.pipe(parser);
parser.resume();
});
parser.on('pause', () => {
this._fileHandler.unpipe(parser);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(this._fileHandler as any).readableFlowing = false;
});
this._fileHandler.on('data', (chunk) => {
readPosition += chunk.length;
});
this._fileHandler.on('error', (err) => {
console.log(err);
reject(err);
});
});
}
catch (err) {
console.log(err);
}
}
}

View File

@@ -0,0 +1,85 @@
import * as pg from 'pg';
import * as importer from 'common/interfaces/importer';
import * as fs from 'fs/promises';
import PostgreSQLParser from '../../parsers/PostgreSQLParser';
import { BaseImporter } from '../BaseImporter';
export default class PostgreSQLImporter extends BaseImporter {
protected _client: pg.PoolClient;
constructor (client: pg.PoolClient, options: importer.ImportOptions) {
super(options);
this._client = client;
}
async import (): Promise<void> {
try {
const { size: totalFileSize } = await fs.stat(this._options.file);
const parser = new PostgreSQLParser();
let readPosition = 0;
let queryCount = 0;
this.emitUpdate({
fileSize: totalFileSize,
readPosition: 0,
percentage: 0,
queryCount: 0
});
return new Promise((resolve, reject) => {
this._fileHandler.pipe(parser);
parser.on('error', reject);
parser.on('close', async () => {
console.log('TOTAL QUERIES', queryCount);
console.log('import end');
resolve();
});
parser.on('data', async (query) => {
queryCount++;
parser.pause();
try {
await this._client.query(query);
}
catch (error) {
this.emit('query-error', {
sql: query,
message: error.hint || error.toString(),
sqlSnippet: error.sql,
time: new Date().getTime()
});
}
this.emitUpdate({
queryCount,
readPosition,
percentage: readPosition / totalFileSize * 100
});
this._fileHandler.pipe(parser);
parser.resume();
});
parser.on('pause', () => {
this._fileHandler.unpipe(parser);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(this._fileHandler as any).readableFlowing = false;
});
this._fileHandler.on('data', (chunk) => {
readPosition += chunk.length;
});
this._fileHandler.on('error', (err) => {
console.log(err);
reject(err);
});
});
}
catch (err) {
console.log(err);
}
}
}

View File

@@ -0,0 +1,103 @@
import { Transform, TransformCallback, TransformOptions } from 'stream';
export default class MySQLParser extends Transform {
private _buffer: string;
private _lastChar: string;
private _last9Chars: string;
encoding: BufferEncoding;
delimiter: string;
isEscape: boolean;
currentQuote: string;
isDelimiter: boolean;
constructor (opts?: TransformOptions & { delimiter: string }) {
opts = {
delimiter: ';',
encoding: 'utf8',
writableObjectMode: true,
readableObjectMode: true,
...opts
};
super(opts);
this._buffer = '';
this._lastChar = '';
this._last9Chars = '';
this.encoding = opts.encoding;
this.delimiter = opts.delimiter;
this.isEscape = false;
this.currentQuote = null;
this.isDelimiter = false;
}
_transform (chunk: Buffer, encoding: BufferEncoding, next: TransformCallback) {
for (const char of chunk.toString(this.encoding)) {
this.checkEscape();
this._buffer += char;
this._lastChar = char;
this._last9Chars += char.trim().toLocaleLowerCase();
if (this._last9Chars.length > 9)
this._last9Chars = this._last9Chars.slice(-9);
this.checkNewDelimiter(char);
this.checkQuote(char);
const query = this.getQuery();
if (query)
this.push(query);
}
next();
}
checkEscape () {
if (this._buffer.length > 0) {
this.isEscape = this._lastChar === '\\'
? !this.isEscape
: false;
}
}
checkNewDelimiter (char: string) {
if (this.currentQuote === null && this._last9Chars === 'delimiter') {
this.isDelimiter = true;
this._buffer = '';
}
else {
const isNewLine = char === '\n' || char === '\r';
if (isNewLine && this.isDelimiter) {
this.isDelimiter = false;
this.delimiter = this._buffer.trim();
this._buffer = '';
}
}
}
checkQuote (char: string) {
const isQuote = !this.isEscape && (char === '\'' || char === '"');
if (isQuote && this.currentQuote === char)
this.currentQuote = null;
else if (isQuote && this.currentQuote === null)
this.currentQuote = char;
}
getQuery () {
if (this.isDelimiter)
return false;
let query: false | string = false;
let demiliterFound = false;
if (this.currentQuote === null && this._buffer.length >= this.delimiter.length)
demiliterFound = this._last9Chars.slice(-this.delimiter.length) === this.delimiter;
if (demiliterFound) {
const parsedStr = this._buffer.trim();
query = parsedStr.slice(0, parsedStr.length - this.delimiter.length);
this._buffer = '';
}
return query;
}
}

View File

@@ -0,0 +1,158 @@
import { Transform, TransformCallback, TransformOptions } from 'stream';
export default class PostgreSQLParser extends Transform {
private _buffer: string;
private _lastChar: string;
private _lastChars: string;
private _bodyWrapper: string;
private _bodyWrapperBuffer: string;
private _firstDollarFound: boolean;
private _isBody: boolean;
private _isSingleLineComment: boolean;
private _isMultiLineComment: boolean;
encoding: BufferEncoding;
delimiter: string;
isEscape: boolean;
currentQuote: string;
isDelimiter: boolean;
constructor (opts?: TransformOptions & { delimiter: string }) {
opts = {
delimiter: ';',
encoding: 'utf8',
writableObjectMode: true,
readableObjectMode: true,
...opts
};
super(opts);
this._buffer = '';
this._lastChar = '';
this._lastChars = '';
this.encoding = opts.encoding;
this.delimiter = opts.delimiter;// ';'
this._bodyWrapper = '';
this._bodyWrapperBuffer = '';
this.isEscape = false;
this.currentQuote = null;
this._firstDollarFound = false;
this._isBody = false;
this._isSingleLineComment = false;
this._isMultiLineComment = false;
}
get _isComment () {
return this._isSingleLineComment || this._isMultiLineComment;
}
_transform (chunk: Buffer, encoding: BufferEncoding, next: TransformCallback) {
for (const char of chunk.toString(this.encoding)) {
this.checkEscape();
this._buffer += char;
this._lastChar = char;
this._lastChars += char;
if (this._lastChars.length > this._bodyWrapper.length)
this._lastChars = this._lastChars.slice(-(this._bodyWrapper.length || 2));
this.checkBodyWrapper(char);
this.checkQuote(char);
this.checkCommentRow();
const query = this.getQuery();
if (query)
this.push(query);
}
next();
}
checkEscape () {
if (this._buffer.length > 0) {
this.isEscape = this._lastChar === '\\'
? !this.isEscape
: false;
}
}
checkCommentRow () {
if (this._isBody) return;
if (!this._isComment) {
if (this.currentQuote === null && this._lastChars.includes('--'))
this._isSingleLineComment = true;
if (this.currentQuote === null && this._lastChars.includes('/*'))
this._isMultiLineComment = true;
}
else {
if (this._isSingleLineComment && (this._lastChar === '\n' || this._lastChar === '\r')) {
this._buffer = '';
this._isSingleLineComment = false;
}
if (this._isMultiLineComment && this._lastChars.includes('*/')) {
this._buffer = '';
this._isMultiLineComment = false;
}
}
}
checkBodyWrapper (char: string) {
if (this._isBody)
this._isBody = this._lastChars !== this._bodyWrapper;
if (this.currentQuote === null && char === '$' && !this._firstDollarFound && !this._bodyWrapper) {
this._firstDollarFound = true;
this._bodyWrapperBuffer += char;
this._isBody = true;
}
else if (this._firstDollarFound) {
if (char === '\n' || char === ' ') {
this._firstDollarFound = false;
this._bodyWrapperBuffer = '';
this._bodyWrapper = '';
this._isBody = false;
return;
}
this._bodyWrapperBuffer += char;
const isEndDollar = char === '$';
if (isEndDollar) {
this._firstDollarFound = false;
this._bodyWrapper = this._bodyWrapperBuffer;
this._bodyWrapperBuffer = '';
}
}
}
checkQuote (char: string) {
const isQuote = !this.isEscape && (char === '\'' || char === '"');
if (isQuote && this.currentQuote === char)
this.currentQuote = null;
else if (isQuote && this.currentQuote === null)
this.currentQuote = char;
}
getQuery () {
if (this._isBody || this._isComment)
return false;
let query: false | string = false;
let demiliterFound = false;
if (this.currentQuote === null && this._buffer.length >= this.delimiter.length)
demiliterFound = this._lastChars.slice(-this.delimiter.length) === this.delimiter;
if (demiliterFound) {
const parsedStr = this._buffer.trim();
query = parsedStr;
this._buffer = '';
this._bodyWrapper = '';
}
return query;
}
}

Some files were not shown because too many files have changed in this diff Show More