Compare commits

...

552 Commits

Author SHA1 Message Date
SPRINX0\prochazka
e76c563471 changelog 2025-02-04 17:05:20 +01:00
SPRINX0\prochazka
fa6388ee6b v6.1.6 2025-02-04 17:04:26 +01:00
SPRINX0\prochazka
fe2e5bc82e v6.1.6-premium-beta.1 2025-02-04 16:48:47 +01:00
SPRINX0\prochazka
e361cb0113 v6.1.6-premuim-beta.1 2025-02-04 16:48:17 +01:00
SPRINX0\prochazka
a12875fde3 dbgate-pro repo ref 2025-02-04 16:48:02 +01:00
SPRINX0\prochazka
b3b94bfb3f 6.1.5 changelog 2025-02-04 16:12:00 +01:00
SPRINX0\prochazka
8e4308bea8 v6.1.5 2025-02-04 16:07:33 +01:00
SPRINX0\prochazka
86736c289b security problem fix #1029 2025-02-04 16:05:25 +01:00
SPRINX0\prochazka
8290100b80 v6.1.4 2025-01-27 12:52:11 +01:00
SPRINX0\prochazka
578e2d3928 changelog 2025-01-27 11:15:50 +01:00
SPRINX0\prochazka
4e5f320777 v6.1.4-beta.3 2025-01-27 11:07:39 +01:00
SPRINX0\prochazka
6b64928a4c Fixed CASE problem in ACE sql-server mode 2025-01-27 11:07:24 +01:00
SPRINX0\prochazka
7f95674113 changelog WIP 2025-01-27 11:04:25 +01:00
SPRINX0\prochazka
f47d082a0d v6.1.4-beta.2 2025-01-27 10:50:17 +01:00
SPRINX0\prochazka
a68a81b339 Show Data/Structure button in one place #1015 2025-01-27 10:40:38 +01:00
SPRINX0\prochazka
e0cf8026ef tab preview mode UX 2025-01-27 10:03:46 +01:00
SPRINX0\prochazka
a1db648318 Data view coloring (every second row) #1014 2025-01-27 09:32:17 +01:00
SPRINX0\prochazka
81ad7eac62 v6.1.4-beta.1 2025-01-24 16:13:09 +01:00
SPRINX0\prochazka
6c9913abaa fixed: Cannot expand tables and views returned from search #1000 2025-01-24 16:12:55 +01:00
SPRINX0\prochazka
e84af5af96 fixed Pin icon misplaced #1007 2025-01-24 14:59:09 +01:00
SPRINX0\prochazka
e574667651 better display of ObjectId on JSON view 2025-01-24 14:33:22 +01:00
SPRINX0\prochazka
4944bc4bca expand all, collapse all commands 2025-01-24 14:27:05 +01:00
SPRINX0\prochazka
c09c5e588a default action settings fix 2025-01-24 12:22:11 +01:00
SPRINX0\prochazka
893b072454 remove log 2025-01-24 12:02:43 +01:00
SPRINX0\prochazka
ba971e4a67 mongodb json view default collection page size #976 2025-01-24 11:47:53 +01:00
Jan Prochazka
82be1df5bf Merge pull request #1011 from dbgate/feature/null-safety-to-sql-generator
fix: ensure extract always return an array
2025-01-23 15:09:23 +01:00
Nybkox
abf5227b47 fix: ensure extract always return an array 2025-01-23 12:20:55 +01:00
SPRINX0\prochazka
0d3e39c479 SSL support for redis #691 2025-01-22 18:42:14 +01:00
SPRINX0\prochazka
d16bc83af0 Merge branch 'feature/redis-key-navigation' 2025-01-22 17:45:01 +01:00
SPRINX0\prochazka
79a246217a redis key selection by keyboard 2025-01-22 17:44:46 +01:00
SPRINX0\prochazka
4ea718b662 redis key navigation 2025-01-22 17:13:33 +01:00
SPRINX0\prochazka
41e5089ab3 redis key loading refactor 2025-01-22 16:35:54 +01:00
SPRINX0\prochazka
db86ae627f Merge branch 'feature/redis' 2025-01-22 09:41:03 +01:00
SPRINX0\prochazka
576fa40c1a redis key load optimalization 2025-01-22 09:40:49 +01:00
SPRINX0\prochazka
8287d5e400 redis loading keys UX 2025-01-22 09:32:26 +01:00
SPRINX0\prochazka
2e030f87a5 redis loading UX 2025-01-22 09:03:09 +01:00
SPRINX0\prochazka
4793bad92f redis load keys optimalization 2025-01-22 08:49:58 +01:00
SPRINX0\prochazka
0c35aefbe2 Redis Format Json #582 2025-01-21 18:36:25 +01:00
SPRINX0\prochazka
7a2390c025 fix 2025-01-21 16:57:44 +01:00
SPRINX0\prochazka
bf3dd2ae88 set redis client name #1004 2025-01-21 16:45:47 +01:00
SPRINX0\prochazka
e5b0cb724b UX fix 2025-01-21 15:58:45 +01:00
SPRINX0\prochazka
f7b520eb30 readme 2025-01-21 12:47:10 +01:00
SPRINX0\prochazka
4ad0782e59 aws build renamed 2025-01-20 15:20:08 +01:00
Jan Prochazka
0755f171ad changelog 2025-01-10 11:48:24 +01:00
Jan Prochazka
48796ec970 v6.1.3 2025-01-10 11:38:42 +01:00
Jan Prochazka
e8d32835d8 v6.1.3-premium-beta.4 2025-01-10 11:11:06 +01:00
SPRINX0\prochazka
56b6864b2c Merge branch 'feature/open-raw' 2025-01-09 17:08:45 +01:00
SPRINX0\prochazka
06be55514c raw data test 2025-01-09 17:07:30 +01:00
SPRINX0\prochazka
183438d2b5 raw data display #991 #962 2025-01-09 16:49:26 +01:00
SPRINX0\prochazka
5208a912a2 raw mode 2025-01-09 16:27:42 +01:00
SPRINX0\prochazka
9f0d8e91ba fixed oracle ILIKE #992 2025-01-09 16:07:14 +01:00
SPRINX0\prochazka
5dbbfe4612 v6.1.3-beta.2 2025-01-09 16:02:59 +01:00
SPRINX0\prochazka
f0eb8945e0 filter model test 2025-01-09 16:01:34 +01:00
SPRINX0\prochazka
d14a1449a3 fixed show detail in fulltest search 2025-01-09 15:45:03 +01:00
SPRINX0\prochazka
b5d0ba1220 data browser tests 2025-01-09 13:51:25 +01:00
SPRINX0\prochazka
436fb24e9f Merge branch 'feature/test-refactor' 2025-01-09 13:35:23 +01:00
SPRINX0\prochazka
df64bd1e84 fix 2025-01-09 13:27:53 +01:00
SPRINX0\prochazka
9457df9378 fix 2025-01-09 12:50:02 +01:00
SPRINX0\prochazka
f7ed9c3eda e2e test refactor 2025-01-09 12:43:32 +01:00
SPRINX0\prochazka
de1a1c923a integr test refactor 2025-01-09 12:30:20 +01:00
SPRINX0\prochazka
dec02f2456 fix 2025-01-09 12:07:33 +01:00
SPRINX0\prochazka
98ba5c7d9a workflow fix 2025-01-09 11:06:14 +01:00
SPRINX0\prochazka
defc92ee23 workflow fix 2025-01-09 11:03:15 +01:00
SPRINX0\prochazka
e9c435c892 cypress tests 2025-01-09 11:02:19 +01:00
Jan Prochazka
de90a314d6 Merge pull request #996 from dbgate/feature/filter-exts
feat: filter extentions on fe
2025-01-09 10:46:46 +01:00
Jan Prochazka
007eb84d22 Merge pull request #993 from dbgate/feature/drop-triggers-and-events
Feature/drop triggers and events
2025-01-09 10:46:17 +01:00
Nybkox
c640fd6df8 Merge pull request #997 from dbgate/feature/nvmrc
feat: add .nvmrc
2025-01-09 09:52:23 +01:00
Nybkox
1b41b44a15 feat: add .nvmrc 2025-01-09 09:51:56 +01:00
Nybkox
9316e68302 feat: filter extentions on fe 2025-01-09 09:36:21 +01:00
SPRINX0\prochazka
89fce420fa try to fix build 2025-01-09 08:43:30 +01:00
SPRINX0\prochazka
a47b060478 fix build 2025-01-09 08:31:07 +01:00
SPRINX0\prochazka
811935f1cd run tests without container 2025-01-09 08:27:24 +01:00
SPRINX0\prochazka
6712c8136f fix 2025-01-08 17:06:53 +01:00
SPRINX0\prochazka
2501cb170f try to use runner local ports for CI tests 2025-01-08 17:01:56 +01:00
SPRINX0\prochazka
3179f2d72c fixed test 2025-01-08 16:48:16 +01:00
SPRINX0\prochazka
9692c0c683 try to fix DEX OAUTH 2025-01-08 16:35:35 +01:00
SPRINX0\prochazka
2deff70218 add connection test 2025-01-08 16:35:16 +01:00
SPRINX0\prochazka
5aee12f543 fixed oauth test redirect 2025-01-08 16:15:49 +01:00
SPRINX0\prochazka
8a4ec82c4c database login - ask user - test connection 2025-01-08 16:14:51 +01:00
SPRINX0\prochazka
11201326fd try to fix dex dockerfile 2025-01-08 15:49:02 +01:00
SPRINX0\prochazka
328c772d35 kill-port didn't help 2025-01-08 15:38:32 +01:00
SPRINX0\prochazka
3f9fd6596d kill port in CY tests 2025-01-08 15:23:18 +01:00
SPRINX0\prochazka
0253b2795e dex config 2025-01-08 15:06:43 +01:00
Jan Prochazka
b25376a790 dex config 2025-01-08 15:05:57 +01:00
SPRINX0\prochazka
01f3f44369 oauth test WIP 2025-01-08 15:05:14 +01:00
Jan Prochazka
a3e8d64d4e dex config 2025-01-08 14:18:46 +01:00
SPRINX0\prochazka
2ee1250ccc dex config 2025-01-08 13:58:14 +01:00
SPRINX0\prochazka
86b1c82384 Merge branch 'feature/dbf' 2025-01-08 13:08:08 +01:00
SPRINX0\prochazka
a156ec942b DBF reader - log errors 2025-01-07 18:28:19 +01:00
SPRINX0\prochazka
48eb8badec fixed import preview 2025-01-07 17:52:26 +01:00
SPRINX0\prochazka
2521f05526 DBF reader plugin 2025-01-07 17:24:56 +01:00
Nybkox
618db79f6b feat: add sql generator to triggers and evets context menu 2025-01-07 16:47:16 +01:00
Nybkox
3089ce8ad6 feat: add triggers and scheduler events to sql generator 2025-01-07 16:35:01 +01:00
Nybkox
dd6021e96a feat: add drop option to triggers and events context menu 2025-01-07 14:57:33 +01:00
Jan Prochazka
79bf9016a3 Merge pull request #985 from dbgate/feature/mysql-event-scheduler
Feature/mysql event scheduler
2025-01-07 14:37:30 +01:00
Nybkox
202716e28c fix: show funcitons specific menu for functions 2025-01-07 14:35:40 +01:00
Nybkox
8c5e23f773 feat: show only 1 of disable/enable actions in events context menu 2025-01-07 14:29:17 +01:00
SPRINX0\prochazka
bf9374bf6e fixed test config 2025-01-07 13:59:42 +01:00
SPRINX0\prochazka
2087574363 Merge branch 'master' of https://github.com/dbgate/dbgate 2025-01-07 13:39:24 +01:00
SPRINX0\prochazka
4765cbcfd4 Merge branch 'feature/portal-test' 2025-01-07 13:39:18 +01:00
SPRINX0\prochazka
a48c23d169 ask user test 2025-01-07 13:38:47 +01:00
Jan Prochazka
03982d4ad2 Merge pull request #981 from dbgate/feature/triggers-sqlite
Feature/triggers sqlite
2025-01-07 13:23:36 +01:00
SPRINX0\prochazka
e531a35f37 ask user portal conn 2025-01-07 13:19:44 +01:00
Nybkox
a8a5864ff0 fix: escape mysql event name in createSql 2025-01-07 13:18:23 +01:00
SPRINX0\prochazka
ee9ce66293 fix test env 2025-01-07 10:55:03 +01:00
SPRINX0\prochazka
a11b87a923 test fix 2025-01-07 10:45:56 +01:00
SPRINX0\prochazka
e3cd01aa2e portal test - import Chinook DB 2025-01-07 10:30:26 +01:00
SPRINX0\prochazka
bf92943a6a portal tests WIP 2025-01-07 09:32:18 +01:00
SPRINX0\prochazka
8d2c2cd62d focus query editor 2025-01-07 09:32:01 +01:00
Nybkox
029f24b079 feat: update dbgate-query-splitter tp 4.11.3 2025-01-07 09:20:59 +01:00
SPRINX0\prochazka
d9ca29b602 portal connection test 2025-01-06 14:56:16 +01:00
SPRINX0\prochazka
ddcfc127b7 Merge branch 'master' of https://github.com/dbgate/dbgate 2025-01-06 11:58:29 +01:00
SPRINX0\prochazka
0659691a72 Merge branch 'feature/ssh-tunnel-test' 2025-01-06 11:57:59 +01:00
SPRINX0\prochazka
4e7c8d8b1e added missing services 2025-01-06 10:42:51 +01:00
SPRINX0\prochazka
f477c03281 increase test timeout 2025-01-06 10:18:40 +01:00
SPRINX0\prochazka
362d4a5a0d test connect too SSH via keyfile 2025-01-06 10:16:58 +01:00
SPRINX0\prochazka
42ad78df58 keyfile - build containers 2025-01-06 09:46:57 +01:00
SPRINX0\prochazka
fef3ffd996 workflow fix 2025-01-06 09:29:27 +01:00
SPRINX0\prochazka
a5f824c778 changed location of mysql-ssh container 2025-01-06 09:00:56 +01:00
SPRINX0\prochazka
4f5bb563e8 JEST timeout 2025-01-06 08:35:15 +01:00
SPRINX0\prochazka
053ba471a6 SSH - handle SSH error 2025-01-06 08:24:14 +01:00
Jan Prochazka
066cd407a9 Merge pull request #986 from dbgate/feature/missing-factories
feat: add missing triggers and events factories
2025-01-05 08:05:02 +01:00
Jan Prochazka
b418dd8d12 Merge pull request #984 from freitasm/master
Update runners.js to fix small typo
2025-01-05 08:02:47 +01:00
Nybkox
1be73d8a4c fix: build enable/disable sql on frontend 2025-01-03 22:57:33 +01:00
SPRINX0\prochazka
aff282d31e ssh tunnel WIP 2025-01-03 16:44:57 +01:00
Nybkox
576a4fc2e5 feat: add missing triggers and events factories 2025-01-03 16:26:10 +01:00
Nybkox
e73356c8da feat: add schedulerEvents to tools 2025-01-03 15:02:03 +01:00
Nybkox
0ffe2d8811 fix: disable rename tests for mysql 2025-01-03 14:59:57 +01:00
Nybkox
c90011fc27 feat: scheduler events tests 2025-01-03 14:59:57 +01:00
Nybkox
891fb15290 feat: add scheduler events to ui 2025-01-03 14:59:57 +01:00
Nybkox
903297a1e9 feat: add scheduler events to analyser 2025-01-03 14:59:57 +01:00
SPRINX0\prochazka
59788faefd workflows 2025-01-03 08:14:49 +01:00
SPRINX0\prochazka
f5a6ca18f0 run test containers - standalone workflow 2025-01-03 08:12:11 +01:00
Mauricio Freitas
30690304bb Update runners.js
Fixed typo "no data retured"
2025-01-03 10:01:29 +13:00
SPRINX0\prochazka
144777da58 SSH - force IPv4 (use 127.0.0.1 instead of localhost) 2025-01-02 17:03:49 +01:00
SPRINX0\prochazka
28a206c7ed upgrade ssh2 2025-01-02 17:03:20 +01:00
SPRINX0\prochazka
72d29a293c skip changed detection 2025-01-02 15:58:15 +01:00
SPRINX0\prochazka
561b43fa13 fix 2025-01-02 15:57:12 +01:00
SPRINX0\prochazka
1e9dc89da1 fixed detection changed files 2025-01-02 15:56:26 +01:00
SPRINX0\prochazka
b4d1b9aa05 fix 2025-01-02 15:35:57 +01:00
SPRINX0\prochazka
77be448b41 fix 2025-01-02 14:13:24 +01:00
SPRINX0\prochazka
1ff2749c9b mysql ssh image 2025-01-02 14:11:07 +01:00
SPRINX0\prochazka
e5fb21daf6 workflows 2025-01-02 14:02:38 +01:00
SPRINX0\prochazka
c1ceea084b ssh connection test 2025-01-02 14:00:18 +01:00
Nybkox
9f4b55ce07 feat: sqlite triggers tests 2025-01-02 11:47:07 +01:00
Nybkox
01b7c42851 fix: prevent testing empty parameters 2025-01-02 11:41:00 +01:00
Nybkox
f0221f6e43 feat: sqlite triggers 2025-01-02 11:26:40 +01:00
Nybkox
30bbdb0f1d refactor: move sqlite queries to sql directory 2025-01-02 11:26:40 +01:00
Nybkox
a6f0bc78d4 fix: always show pin icon on the right 2025-01-02 10:59:22 +01:00
Jan Prochazka
ceb6a88964 Merge branch 'feature/workflow-refactor' 2024-12-30 15:25:39 +01:00
Jan Prochazka
a39fff8b3a ssh tunnel test disabled 2024-12-30 15:25:23 +01:00
Jan Prochazka
0cf3d5993c generated header 2024-12-30 08:28:25 +01:00
Jan Prochazka
2966484cda v6.1.3-beta.1 2024-12-30 08:23:36 +01:00
Jan Prochazka
ac3bb58106 generated workflows 2024-12-30 08:23:18 +01:00
Jan Prochazka
36e2f1bdee workflow templates 2024-12-30 08:11:18 +01:00
Jan Prochazka
70083bd870 workflows - defs support 2024-12-30 07:05:25 +01:00
Jan Prochazka
f7b39fca26 code cleanup 2024-12-29 09:57:33 +01:00
Jan Prochazka
70873e83bd docker pipeline refactor 2024-12-29 09:57:18 +01:00
Jan Prochazka
2858bba8b2 yaml replace changed 2024-12-28 21:16:52 +01:00
Jan Prochazka
bd0404fbaf fixes 2024-12-28 15:36:05 +01:00
Jan Prochazka
317f6256f6 fix 2024-12-28 15:28:34 +01:00
Jan Prochazka
6c9b738717 fix 2024-12-28 15:10:45 +01:00
Jan Prochazka
2f8c584af5 workflows 2024-12-28 15:03:38 +01:00
Jan Prochazka
d3b417679e workflow processor 2024-12-28 15:00:59 +01:00
Jan Prochazka
00dd8bfc72 fixed links to dbgate.org 2024-12-28 14:01:19 +01:00
Jan Prochazka
e1eea4adf3 fixed links to dbgate.org 2024-12-28 11:30:18 +01:00
Jan Prochazka
fd2d2e90d4 workflow refactor WIP 2024-12-27 08:34:17 +01:00
Jan Prochazka
f97b70ce45 v6.1.2 2024-12-26 08:05:17 +01:00
Jan Prochazka
45d79478fb workflow fixes 2024-12-26 08:05:03 +01:00
Jan Prochazka
a59f42bd62 v6.1.2-premium-beta.18 2024-12-26 07:47:14 +01:00
Jan Prochazka
a189fa7b6d fix 2024-12-26 07:46:58 +01:00
Jan Prochazka
794bc97207 v6.1.2-beta.17 2024-12-26 07:45:27 +01:00
Jan Prochazka
24f7def7ab v6.1.2-premium-beta.16 2024-12-26 07:45:16 +01:00
Jan Prochazka
01071c236e notarization log 2024-12-26 07:44:53 +01:00
Jan Prochazka
a6326ac9fa v6.1.2-premium-beta.15 2024-12-26 07:37:36 +01:00
Jan Prochazka
4c6d409be8 print notarization log 2024-12-26 07:37:19 +01:00
Jan Prochazka
44ad8e51a5 v6.1.2-premium-beta.14 2024-12-26 07:18:26 +01:00
Jan Prochazka
e82578adfb v6.1.2-beta.14 2024-12-26 07:17:52 +01:00
Jan Prochazka
24f28b559e pro app build 2024-12-26 07:17:24 +01:00
Jan Prochazka
b086a5d3d2 prevent double upload snap 2024-12-25 21:32:17 +01:00
Jan Prochazka
bb0b87b770 v6.1.2-beta.13 2024-12-25 20:20:26 +01:00
Jan Prochazka
aa4f82fa98 fix 2024-12-25 20:20:10 +01:00
Jan Prochazka
873ace4170 v6.1.2-beta.12 2024-12-25 19:51:24 +01:00
Jan Prochazka
5a9d8ba0a7 fix 2024-12-25 19:51:16 +01:00
Jan Prochazka
07f0fdcc1c v6.1.2-beta.11 2024-12-25 19:43:27 +01:00
Jan Prochazka
ff7ee4fb98 fix 2024-12-25 19:43:16 +01:00
Jan Prochazka
b1f5b62757 v6.1.2-beta.10 2024-12-25 19:39:37 +01:00
Jan Prochazka
a67c857204 python 3.11 fix 2024-12-25 19:39:26 +01:00
Jan Prochazka
4032c53a30 v6.1.2-beta.9 2024-12-25 12:19:09 +01:00
Jan Prochazka
0a37ed74d9 electron reverted to version 30 2024-12-25 12:18:58 +01:00
Jan Prochazka
f07efe440a v6.1.2-beta.8 2024-12-25 12:09:35 +01:00
Jan Prochazka
2d5e67802d removed mongodb-client-encryption from community build 2024-12-25 12:09:25 +01:00
Jan Prochazka
7b8e013084 v6.1.2-beta.7 2024-12-25 11:29:42 +01:00
Jan Prochazka
b69fc04b5c try to upgrade electron 2024-12-25 11:29:23 +01:00
Jan Prochazka
b6dfdd4741 v6.1.2-beta.6 2024-12-25 11:14:10 +01:00
Jan Prochazka
ff3985a542 upgraded mongodb-client-encryption 2024-12-25 11:13:54 +01:00
Jan Prochazka
9c7e1dcaf1 v6.1.2-beta.5 2024-12-25 10:44:39 +01:00
Jan Prochazka
48eb09687c app build - node version 22 2024-12-25 10:44:02 +01:00
Jan Prochazka
86b339535d updated electron builder 2024-12-25 10:42:49 +01:00
Jan Prochazka
576b6dc774 v6.1.2-beta.4 2024-12-25 10:28:26 +01:00
Jan Prochazka
18ca971f67 try to use electron notarize 2024-12-25 10:28:10 +01:00
Jan Prochazka
3916a5e6e8 fixed ssh tunnel connection test #972 #973 2024-12-25 09:49:23 +01:00
Jan Prochazka
1446fdad5e v6.1.2-beta.3 2024-12-23 09:52:31 +01:00
Jan Prochazka
1478886e04 fix 2024-12-23 09:52:22 +01:00
Jan Prochazka
54d61790a9 v6.1.2-beta.2 2024-12-23 09:27:28 +01:00
Jan Prochazka
bb638fd8db fix 2024-12-23 09:27:14 +01:00
Jan Prochazka
e3a2589517 v6.1.2-beta.1 2024-12-23 09:21:42 +01:00
Jan Prochazka
6f557a6463 print notarization error 2024-12-23 09:21:31 +01:00
Jan Prochazka
323f27f6e4 changelog 2024-12-23 07:06:36 +01:00
Jan Prochazka
8d4a38dccb v6.1.1 2024-12-23 07:06:12 +01:00
SPRINX0\prochazka
54a3b30e83 Merge branch 'master' of https://github.com/dbgate/dbgate 2024-12-20 13:45:41 +01:00
SPRINX0\prochazka
6251bcd8fd changelog 2024-12-20 13:45:39 +01:00
SPRINX0\prochazka
e42099c1a9 v6.1.1-beta.1 2024-12-20 12:57:25 +01:00
Jan Prochazka
b07ee91cf9 fixed oracle export + clickhouse test 2024-12-20 12:23:29 +01:00
Jan Prochazka
62c028fc3c export test finished 2024-12-20 11:33:28 +01:00
SPRINX0\prochazka
07ea575b0f fixed postgres export + export tests #970 2024-12-20 11:17:43 +01:00
SPRINX0\prochazka
ee78786974 #968 mysql table comment fix 2024-12-20 10:47:14 +01:00
SPRINX0\prochazka
e1814663cd trigger fulltext search 2024-12-20 10:40:57 +01:00
SPRINX0\prochazka
6ae3e019ff ux 2024-12-20 10:38:29 +01:00
Jan Prochazka
cadf539c3d fixed diff for triggers 2024-12-20 10:30:05 +01:00
Jan Prochazka
51929d7ef7 some tests fixed 2024-12-20 10:23:49 +01:00
Jan Prochazka
0edc7f077f test trigger createSql 2024-12-20 09:26:53 +01:00
SPRINX0\prochazka
2488cee7ea test definition refactor 2024-12-20 09:03:30 +01:00
SPRINX0\prochazka
edf64db69a search settings improvement 2024-12-20 08:42:30 +01:00
SPRINX0\prochazka
c65bf51dcd Merge branch 'feature/parameters-oracle' 2024-12-20 07:46:51 +01:00
Nybkox
effe235a95 feat: oracle parameters 2024-12-19 16:06:56 +01:00
Nybkox
583d1494c2 feat: fallback to position if param does not have name 2024-12-19 12:50:50 +01:00
Nybkox
983daf0d1c feat: add options position to params typing 2024-12-19 12:09:25 +01:00
Jan Prochazka
756ddf1a8b Merge pull request #969 from dbgate/feature/triggers
Feature/triggers
2024-12-19 12:09:08 +01:00
Nybkox
9ccd647d97 fix: update triggers typing to cover all oracle timing options 2024-12-19 11:55:22 +01:00
Nybkox
dc9bfdc553 fix: update pssql triggers query to match ts def 2024-12-19 10:50:39 +01:00
Nybkox
af4e91faba fix: update oracle triggers test create queries 2024-12-19 10:46:40 +01:00
Nybkox
394020157b fix: update oracle triggers tests expected values 2024-12-19 10:26:48 +01:00
Nybkox
f16aab12e1 fix: add trigger event type to oracle triggers query 2024-12-19 10:17:16 +01:00
Nybkox
e08216d6dd feat: mssql triggers tests 2024-12-19 10:13:15 +01:00
Nybkox
ebb4f8e73e fix: mssql triggers query naming 2024-12-19 10:13:04 +01:00
Nybkox
b9939e5d5f fix: correctly map mysql triggers sql output 2024-12-19 09:58:54 +01:00
Nybkox
9eb3bca8d6 feat: add other create/drop for triggers tests 2024-12-19 09:54:17 +01:00
Nybkox
022f263bf9 fix: update pssql triggers test sql 2024-12-19 09:53:47 +01:00
Nybkox
56972652d5 fix: pssql triggers - map tgtype to timing / event type correctly 2024-12-19 09:53:11 +01:00
SPRINX0\prochazka
d75b9e2688 ace-builds patch #954 2024-12-19 09:21:57 +01:00
Nybkox
d2c5440e39 feat: pssql tirgger test 2024-12-19 08:33:26 +01:00
Jan Prochazka
8ff30e426e fix - expand limited when accessing bykeyboard nav 2024-12-18 14:13:01 +01:00
Jan Prochazka
7cdbef609e arm-64 builds 2024-12-18 10:59:21 +01:00
Jan Prochazka
f6195a468d v6.1.0 2024-12-18 10:37:54 +01:00
Jan Prochazka
c23bf72d55 changelog 2024-12-18 10:35:54 +01:00
Jan Prochazka
c02441402b fixed search in list 2024-12-18 10:22:02 +01:00
Jan Prochazka
b9a8764b55 fixed search 2024-12-18 10:01:52 +01:00
Jan Prochazka
a2374c1981 v6.0.1-beta.6 2024-12-18 09:39:57 +01:00
Jan Prochazka
9cfd5af704 prevent jump to first item when focusing because of mouse 2024-12-18 09:37:40 +01:00
Jan Prochazka
a6f473b8ed better connection UX 2024-12-18 09:08:42 +01:00
Jan Prochazka
e0a74402cb dropdown for default database 2024-12-18 08:43:51 +01:00
Jan Prochazka
c6e57b278e use default database 2024-12-18 08:18:09 +01:00
Jan Prochazka
e63f1f8f09 clickAction refactor, settings - open detail after keyboard navigation 2024-12-18 08:08:45 +01:00
Nybkox
e866c019f0 feat: mysql and oracle triggers tests 2024-12-18 06:09:30 +01:00
Nybkox
5f4bd6d3e3 fix: triggers typing and yaml conv 2024-12-18 06:05:49 +01:00
SPRINX0\prochazka
57da9c9885 changelog wip 2024-12-17 17:17:31 +01:00
SPRINX0\prochazka
e6a3acf4c2 search GUI improved 2024-12-17 16:27:54 +01:00
SPRINX0\prochazka
537869e862 data grid - no rows info 2024-12-17 16:03:21 +01:00
SPRINX0\prochazka
ae2ff7b3b1 fixed display CLOB an NCLOB columns in Oracle #944 2024-12-17 15:31:10 +01:00
SPRINX0\prochazka
1db01dbdb1 optimalization 2024-12-17 14:59:44 +01:00
SPRINX0\prochazka
7988438dc7 fix search connections 2024-12-17 14:43:05 +01:00
SPRINX0\prochazka
3b32823f94 v6.0.1-beta.5 2024-12-17 14:29:56 +01:00
SPRINX0\prochazka
3370c754f2 try to fix postgres plugin 2024-12-17 14:29:45 +01:00
SPRINX0\prochazka
2d84e5a611 dataGrid align numbers right #957 2024-12-17 13:43:21 +01:00
SPRINX0\prochazka
8d5f73849e upgraded ace-builds #954 2024-12-17 12:42:09 +01:00
SPRINX0\prochazka
7a5019164a configurable search in connections 2024-12-17 12:26:50 +01:00
SPRINX0\prochazka
f5733ea2d7 handle camelCase in tokenizer 2024-12-17 10:16:19 +01:00
Nybkox
413287c691 fix: remove triggerName 2024-12-17 10:16:07 +01:00
Nybkox
9e941dfce2 feat: add triggers to ui 2024-12-17 10:16:07 +01:00
Nybkox
d32af771dc fix: add purename to trigger analysers 2024-12-17 10:16:07 +01:00
Nybkox
1c84f40bcf feat: add triggers loading message 2024-12-17 10:16:06 +01:00
Nybkox
671eba22e0 feat: add oracle triggers to analyser 2024-12-17 10:16:06 +01:00
Nybkox
c00cb3076c feat: add mysql triggers to analyser 2024-12-17 10:16:06 +01:00
Nybkox
62daa13e54 feat: add mssql triggers to analyser 2024-12-17 10:16:06 +01:00
Nybkox
4cc0a66a7d feat: add pssql triggers to analyser 2024-12-17 10:16:06 +01:00
SPRINX0\prochazka
92e13220d8 tokenized search in references 2024-12-17 10:12:45 +01:00
SPRINX0\prochazka
2a5fdd852a search tokenizer optimalization 2024-12-17 10:09:52 +01:00
SPRINX0\prochazka
7759fd862f ability to disable tab preview mode 2024-12-17 09:34:16 +01:00
SPRINX0\prochazka
ca5dd0ac30 v6.0.1-beta.4 2024-12-16 17:01:39 +01:00
SPRINX0\prochazka
18be29fd88 Merge branch 'feature/search' 2024-12-16 17:01:26 +01:00
SPRINX0\prochazka
6ea54a5b0a tokenized column search 2024-12-16 17:01:05 +01:00
SPRINX0\prochazka
5d294f6236 camel search tokenizer 2024-12-16 16:58:10 +01:00
SPRINX0\prochazka
5544b6291b search tokenizer 2024-12-16 16:50:17 +01:00
SPRINX0\prochazka
bf4841bca4 filter name optimalization 2024-12-16 16:23:55 +01:00
SPRINX0\prochazka
358a641449 refactor - not working 2024-12-16 15:53:52 +01:00
SPRINX0\prochazka
7e1ceb69ae UX fix 2024-12-16 15:36:26 +01:00
SPRINX0\prochazka
939f04ae62 optimalization 2024-12-16 15:19:54 +01:00
SPRINX0\prochazka
2fc2ac491c find in SQL text 2024-12-16 14:45:38 +01:00
SPRINX0\prochazka
20a5a50516 rename file 2024-12-16 14:10:18 +01:00
SPRINX0\prochazka
0932f4c537 search columns WIP 2024-12-16 14:08:19 +01:00
SPRINX0\prochazka
c46c9a4e16 lisgt matcher refactor 2024-12-16 13:08:59 +01:00
SPRINX0\prochazka
a20b4b3339 search settings 2024-12-16 11:47:53 +01:00
SPRINX0\prochazka
dc302f89c7 Display comments into TABLES and COLUMNS lists #755 2024-12-16 09:46:07 +01:00
SPRINX0\prochazka
f5a2d142e2 fixed [MSSQL] Foreign keys show up in a weird way #734 2024-12-16 08:26:25 +01:00
SPRINX0\prochazka
1020a5820b Merge branch 'master' of https://github.com/dbgate/dbgate 2024-12-13 16:27:17 +01:00
SPRINX0\prochazka
deb13505b8 fixed loading constraints #734 2024-12-13 16:27:14 +01:00
Jan Prochazka
71c06e31f7 sql terminator in oracle routines 2024-12-13 15:06:12 +01:00
Jan Prochazka
a203480a72 oracle function tests 2024-12-13 15:06:12 +01:00
Jan Prochazka
c0fcd681be oracle procedure & function analyser 2024-12-13 15:06:12 +01:00
Jan Prochazka
7402bb6823 test fix 2024-12-13 15:06:11 +01:00
Jan Prochazka
35d791bee4 fixed some tests 2024-12-13 15:06:11 +01:00
Jan Prochazka
ad4a599800 oracle view fix 2024-12-13 15:06:11 +01:00
Jan Prochazka
33db85f03b oracle tests 2024-12-13 15:06:11 +01:00
Jan Prochazka
ec5d05fc26 oracle fixes 2024-12-13 15:06:11 +01:00
Jan Prochazka
face7ecdb5 rename sql object oracle 2024-12-13 15:06:11 +01:00
Jan Prochazka
6035319035 uncommented oracle container for tests 2024-12-13 15:06:11 +01:00
Jan Prochazka
e698da71fb oracle tests - run on CI 2024-12-13 15:06:11 +01:00
Jan Prochazka
b466de781a oracle - rename table, deploy scripts passes 2024-12-13 15:06:11 +01:00
Jan Prochazka
e5d583310d merged tests pipelines 2024-12-13 15:06:11 +01:00
Jan Prochazka
f72dbf19c2 driver tests 2024-12-13 15:06:11 +01:00
Jan Prochazka
10538a04b4 oracle import pass 2024-12-13 15:06:11 +01:00
Jan Prochazka
d71452a397 oracle - implemented scope identity 2024-12-13 15:06:11 +01:00
Jan Prochazka
3f45bfcdd0 select scope identity test 2024-12-13 15:06:11 +01:00
Jan Prochazka
545e9863b6 fix identity test 2024-12-13 15:06:11 +01:00
Jan Prochazka
a37f2a5240 select scope identity test 2024-12-13 15:06:11 +01:00
Jan Prochazka
d6b4c0a96b oracle alter table passes 2024-12-13 15:06:11 +01:00
Jan Prochazka
d56e917b3f oracle query spec passed 2024-12-13 15:06:11 +01:00
Jan Prochazka
860c811504 oracle table-create test passes 2024-12-13 15:06:11 +01:00
Jan Prochazka
c93e8c35ec table-analyse oracle tests pass 2024-12-13 15:06:11 +01:00
Jan Prochazka
5278e5da0c fixed oracle index analyser 2024-12-13 15:06:11 +01:00
Jan Prochazka
e7e3c307fc table analyse refactor (works on oracle) 2024-12-13 15:06:11 +01:00
Jan Prochazka
e9af85038e try to use smaller oracle image 2024-12-13 15:06:11 +01:00
Jan Prochazka
bf04721e36 run oracle tests on CI 2024-12-13 15:06:11 +01:00
SPRINX0\prochazka
a810dc4204 focused connection changes 2024-12-13 10:48:42 +01:00
Jan Prochazka
faad82fc34 Merge pull request #961 from dbgate/feature/postgis-geo
feat: transform geography binary data to wkt
2024-12-12 16:47:29 +01:00
Nybkox
b8ae53db7d feat: transform geography binary data to wkt 2024-12-12 16:37:54 +01:00
Jan Prochazka
1571295ab6 focus UX 2024-12-12 16:29:12 +01:00
Jan Prochazka
d3cc3a92c1 v6.0.1-beta.3 2024-12-12 16:15:18 +01:00
Jan Prochazka
381dc6a535 Add apple silicon only build #949 2024-12-12 16:15:03 +01:00
Jan Prochazka
6b9df571af handler UX scroll problem 2024-12-12 16:06:36 +01:00
Jan Prochazka
897547371e configurable connection click, database click #959 2024-12-12 15:53:00 +01:00
Jan Prochazka
bf85a922ca first oracle test works 2024-12-10 16:03:26 +01:00
Jan Prochazka
00525f6b81 oracle tests WIP 2024-12-10 15:40:15 +01:00
SPRINX0\prochazka
6dd27eb34f basic auth check config #934 2024-12-10 13:11:03 +01:00
SPRINX0\prochazka
0b30386fee e2e test config 2024-12-10 08:48:53 +01:00
SPRINX0\prochazka
1f7f0ea8a2 Merge branch 'feature/e2e-tests' 2024-12-10 08:33:52 +01:00
SPRINX0\prochazka
0ae0cee766 renamed test job 2024-12-10 08:33:28 +01:00
SPRINX0\prochazka
4cbc7f3ae5 connect test 2024-12-09 17:22:29 +01:00
SPRINX0\prochazka
f1cd0ab689 fix tests 2024-12-09 17:13:32 +01:00
SPRINX0\prochazka
7f367a1f84 test fixes 2024-12-09 16:52:02 +01:00
SPRINX0\prochazka
5405b9bf72 cypress run server inline test 2024-12-09 16:32:56 +01:00
SPRINX0\prochazka
75f75d95a6 ux tests 2024-12-09 15:41:50 +01:00
SPRINX0\prochazka
ae5c539e31 UI tests 2024-12-09 15:33:45 +01:00
SPRINX0\prochazka
e7797cedc1 try to fix test 2024-12-09 15:11:38 +01:00
SPRINX0\prochazka
f3c3ddd73a e2e on CI 2024-12-09 14:51:56 +01:00
SPRINX0\prochazka
c201f06103 fixed workflow 2024-12-09 13:45:40 +01:00
SPRINX0\prochazka
111a3a678f cypress test WIP 2024-12-09 13:44:08 +01:00
SPRINX0\prochazka
51c4964003 fixed deps 2024-12-06 16:48:15 +01:00
SPRINX0\prochazka
5fac064a48 update deps 2024-12-06 16:41:22 +01:00
SPRINX0\prochazka
e84f45ae39 fix 2024-12-06 16:39:56 +01:00
SPRINX0\prochazka
7e119d40a4 e2e tests 2024-12-06 16:38:42 +01:00
SPRINX0\prochazka
22b47d1066 e2e test in github 2024-12-06 16:12:51 +01:00
SPRINX0\prochazka
ac0ea6a937 cy - connect to mysql 2024-12-06 15:46:23 +01:00
SPRINX0\prochazka
ed7bfe0c21 e2e tests branch 2024-12-06 14:36:59 +01:00
SPRINX0\prochazka
55cac14ecf v6.0.1-packer-beta.2 2024-12-06 14:14:39 +01:00
SPRINX0\prochazka
691635c5d1 changed volatile deps 2024-12-06 14:14:27 +01:00
SPRINX0\prochazka
9209a2d7d3 v6.0.1-packer-beta.1 2024-12-06 13:16:08 +01:00
Jan Prochazka
05b044d965 Merge pull request #953 from dbgate/featrue/callable-templates
feat: myssql callable template
2024-12-05 15:40:43 +01:00
Nybkox
e231a3a41a feat: pssql callable template 2024-12-05 15:32:33 +01:00
Nybkox
216614a4b1 feat: allow dollar dollar string in query params 2024-12-05 15:32:23 +01:00
Nybkox
ae19d14951 feat: add return type to pssql funcs 2024-12-05 15:31:50 +01:00
Nybkox
7f639361b8 feat: myssql callable template 2024-12-05 12:45:49 +01:00
SPRINX0\prochazka
ba706b85d3 changelog 2024-12-05 12:25:13 +01:00
SPRINX0\prochazka
3b91d921e8 v6.0.0 2024-12-05 12:11:30 +01:00
SPRINX0\prochazka
660555d664 v6.0.0-premium-beta.6 2024-12-05 10:20:52 +01:00
SPRINX0\prochazka
3550710f23 fix 2024-12-05 10:20:18 +01:00
SPRINX0\prochazka
1429c29537 v6.0.0-premium-beta.5 2024-12-05 10:16:26 +01:00
SPRINX0\prochazka
95113490f1 disabled aws build 2024-12-05 10:16:11 +01:00
SPRINX0\prochazka
1eafdb944a fix redirect 2024-12-05 10:15:32 +01:00
SPRINX0\prochazka
a32cd0b2ae typo 2024-12-05 09:56:24 +01:00
SPRINX0\prochazka
249fbf3f96 v6.0.0-beta.4 2024-12-04 14:39:43 +01:00
SPRINX0\prochazka
64877af64a changed build envfrom macos12 to macos14 2024-12-04 14:39:32 +01:00
SPRINX0\prochazka
ff94e46179 v6.0.0-beta.3 2024-12-04 14:19:13 +01:00
SPRINX0\prochazka
921bd4613a fix 2024-12-04 14:17:42 +01:00
SPRINX0\prochazka
6f4a49ea97 refactor 2024-12-04 14:15:13 +01:00
SPRINX0\prochazka
9029fccad4 default parameter encoding for execute scripts 2024-12-04 13:45:12 +01:00
SPRINX0\prochazka
edf3a072c5 tsql call 2024-12-04 13:27:20 +01:00
SPRINX0\prochazka
0fde8c49a7 generate SQL - execute procedure TSQL 2024-12-04 13:15:06 +01:00
SPRINX0\prochazka
767c835a8e parameters in db struct extender 2024-12-04 12:40:12 +01:00
SPRINX0\prochazka
38f0223dc0 UX 2024-12-04 10:51:26 +01:00
SPRINX0\prochazka
ec707b5af3 up-to-date sql object info tab 2024-12-04 10:44:43 +01:00
SPRINX0\prochazka
462d5e3187 removed schemaName from mysql 2024-12-04 10:23:16 +01:00
SPRINX0\prochazka
5cc4c07941 fix - mysql has not schema 2024-12-04 10:16:58 +01:00
SPRINX0\prochazka
20de78f88a table editor - mark tab unsaved 2024-12-04 10:00:03 +01:00
SPRINX0\prochazka
a63d70ca7e handled "driver not found" error 2024-12-04 09:52:06 +01:00
SPRINX0\prochazka
672d6b88b2 Merge branch 'master' of https://github.com/dbgate/dbgate 2024-12-04 07:46:06 +01:00
SPRINX0\prochazka
add1612c92 6.0 changelog 2024-12-04 07:46:04 +01:00
Jan Prochazka
96b964e609 Merge pull request #952 from dbgate/feature/mariadb-indexes-collation
feat: add collation to maria db indexes query and analyser
2024-12-04 07:07:56 +01:00
Nybkox
6b40190097 feat: add collation to maria db indexes query and analyser 2024-12-03 19:28:16 +01:00
SPRINX0\prochazka
f5b0bc5605 v6.0.0-premium-beta.2 2024-12-03 18:00:43 +01:00
SPRINX0\prochazka
64a58252e5 reverted tmp change 2024-12-03 17:56:51 +01:00
SPRINX0\prochazka
46571684f6 v6.0.0-alpha.1 2024-12-03 17:52:09 +01:00
SPRINX0\prochazka
710022539b tmp change 2024-12-03 17:51:36 +01:00
SPRINX0\prochazka
bc75d559b0 fix 2024-12-03 17:50:53 +01:00
SPRINX0\prochazka
a82ee5cc65 v6.0.0-alpha.1 2024-12-03 17:41:51 +01:00
SPRINX0\prochazka
6647dd16f8 tmp version change 2024-12-03 17:41:12 +01:00
SPRINX0\prochazka
6f4e1e07f7 fix - build pro NPM 2024-12-03 17:39:50 +01:00
SPRINX0\prochazka
5cd951a9c1 v6.0.0-alpha.1 2024-12-03 17:25:52 +01:00
SPRINX0\prochazka
f492a215b4 changed NPM versions to 6.0 2024-12-03 17:22:37 +01:00
SPRINX0\prochazka
bbd2d74a28 v5.5.7-beta.69 2024-12-03 17:00:57 +01:00
SPRINX0\prochazka
2b697e21ba Merge branch 'master' of https://github.com/dbgate/dbgate 2024-12-03 17:00:46 +01:00
SPRINX0\prochazka
3a4e4ecbdc fix 2024-12-03 17:00:44 +01:00
SPRINX0\prochazka
05cbb915d6 v5.5.7-alpha.68 2024-12-03 16:38:01 +01:00
SPRINX0\prochazka
26a2bb75fa v5.5.7-beta.67 2024-12-03 16:35:18 +01:00
Jan Prochazka
71b0bb78ec Merge pull request #947 from dbgate/feature/parameters
Feature/parameters
2024-12-03 16:27:28 +01:00
Nybkox
4e4eb39a19 fix: remove distinct from mysql params query 2024-12-03 16:19:57 +01:00
Jan Prochazka
b6399c8271 try to fix test 2024-12-03 16:05:23 +01:00
SPRINX0\prochazka
eb4a764407 correctly show focus in form view 2024-12-03 15:41:46 +01:00
Nybkox
27188eb2c5 fix: normalize type name for mysql params 2024-12-03 15:39:22 +01:00
Nybkox
57a997adc3 fix: expect decimal for numeric params in mysql tests 2024-12-03 15:39:05 +01:00
Nybkox
a72a03cc3a fix: add null safety for mysql function w/o params 2024-12-03 15:33:11 +01:00
Nybkox
bb185d9e9f fix: add join on schema for mysql params query 2024-12-03 15:32:33 +01:00
Nybkox
0298660714 fix: add shchema to mysql programables query 2024-12-03 15:32:21 +01:00
SPRINX0\prochazka
8bf1dbb10d recent & unsaved connection folder 2024-12-03 15:30:02 +01:00
SPRINX0\prochazka
8e5ef98a7c unsaved connections limit 2024-12-03 15:20:28 +01:00
SPRINX0\prochazka
72bd536aec show unsaved connections in connection tree 2024-12-03 14:54:22 +01:00
Nybkox
1a4009a6b2 chore: remove unused query results 2024-12-03 14:13:31 +01:00
Nybkox
e40357c052 fix: replace fullDataType with dataType in mssql params 2024-12-03 14:11:26 +01:00
Nybkox
222ea07cf2 fix: update mssql params queries 2024-12-03 14:11:04 +01:00
SPRINX0\prochazka
6b3f398de3 fixed keyboard navigation 2024-12-03 13:53:06 +01:00
SPRINX0\prochazka
d796fa7ff4 connection menu refactor 2024-12-03 13:37:36 +01:00
SPRINX0\prochazka
6fdfd8717f Open form removed from default actions 2024-12-03 13:31:26 +01:00
Nybkox
81cea4c0f2 fix: pssql params to string helper 2024-12-03 13:07:50 +01:00
SPRINX0\prochazka
6a64633650 fixed menu for non-mac 2024-12-03 13:07:02 +01:00
Nybkox
21702f1593 fix: do not fetch pssql params w/o name 2024-12-03 13:03:05 +01:00
Nybkox
32ddb9c4c7 fix: normalize pssql parameters datatype 2024-12-03 13:02:46 +01:00
Nybkox
10fc62ceb7 fix: do not order pssql params by name 2024-12-03 13:02:40 +01:00
Nybkox
d3018a3136 fix: correct function name in tests 2024-12-03 13:02:39 +01:00
Jan Prochazka
f9bcbd588b mac keyboard menu 2024-12-03 12:52:04 +01:00
Nybkox
5c7d2bfd85 fix: update parameter group keys 2024-12-03 11:01:47 +01:00
SPRINX0\prochazka
788f0ebf77 show error for current connection 2024-12-03 10:53:59 +01:00
Nybkox
0eca5dd95d fix: typos 2024-12-03 10:37:36 +01:00
SPRINX0\prochazka
47322b0bbb expand/collapse tables 2024-12-03 10:23:54 +01:00
SPRINX0\prochazka
518a05a6f0 expand/collapse DB with keyboard 2024-12-03 10:16:51 +01:00
Jan Prochazka
352e426e17 fix 2024-12-03 09:48:56 +01:00
Jan Prochazka
666122f265 add mysql create/drop procedure test 2024-12-03 09:46:12 +01:00
SPRINX0\prochazka
61e32f6d95 query designer moved to premium 2024-12-03 08:39:05 +01:00
SPRINX0\prochazka
7aabc8f0be refresh licenses 2024-12-02 17:36:56 +01:00
Jan Prochazka
a66dc03b99 params test - added object for test parent object match 2024-11-29 10:48:15 +01:00
Jan Prochazka
cf5ecb3150 test create SQL 2024-11-29 10:44:09 +01:00
Jan Prochazka
46c365c5cd mysql parameter types 2024-11-29 10:29:12 +01:00
Jan Prochazka
ea76751e4a postgres function tests 2024-11-29 10:06:34 +01:00
Jan Prochazka
0bef3f8e71 postgre procedure type tests 2024-11-29 09:57:46 +01:00
Jan Prochazka
c26c9fae12 mssql parameters test 2024-11-29 09:35:15 +01:00
Jan Prochazka
446c615bb8 typo 2024-11-29 08:47:13 +01:00
Nybkox
c516873541 feat: add parameters to mysql 2024-11-28 21:35:26 +01:00
Nybkox
d4326de087 fix: proceduresParameters mssql query 2024-11-28 21:07:59 +01:00
Nybkox
eca966bb90 fix: add null safety to getParametersSqlString 2024-11-28 21:07:59 +01:00
Nybkox
262b4732e3 feat: use parameterMode instead of isOutputParameter 2024-11-28 21:07:59 +01:00
Nybkox
7f9a30f568 fix: add missing conditions for pssql parameters query 2024-11-28 21:07:59 +01:00
Nybkox
a89d2e1365 fix: add missing conditions for mssql parameters queries 2024-11-28 21:07:59 +01:00
Nybkox
fcd6f6c8fc fix: correcttly map parameters to object list 2024-11-28 21:07:59 +01:00
Nybkox
8313d7f9f1 fix: update mssql parameters query to match ParameterInfo 2024-11-28 21:07:59 +01:00
Nybkox
3a12601103 feat: add parameters to createSql for pssql 2024-11-28 21:07:59 +01:00
Nybkox
926949dc89 fix: remove redundant field from ParameterInfo 2024-11-28 21:07:59 +01:00
Nybkox
6b155083ef feat: stored procedures and funciton parameters support for pssql 2024-11-28 21:07:59 +01:00
Nybkox
2b2ecac3ab feat: stored procedures and funciton parameters support for mssql 2024-11-28 21:07:59 +01:00
Jan Prochazka
35e9ff607d v5.5.7-beta.66 2024-11-28 18:47:35 +01:00
Jan Prochazka
ae037834f2 connections UX 2024-11-28 18:45:39 +01:00
Jan Prochazka
3ac24436ba focused connection widget 2024-11-28 18:17:22 +01:00
Jan Prochazka
2ca17e826c connection tree UX 2024-11-28 17:53:22 +01:00
SPRINX0\prochazka
4fb6128499 v5.5.7-premium-beta.65 2024-11-28 15:12:52 +01:00
SPRINX0\prochazka
c359332746 v5.5.7-beta.64 2024-11-28 15:11:54 +01:00
SPRINX0\prochazka
1cd8e8e376 typo 2024-11-28 15:02:27 +01:00
SPRINX0\prochazka
48ec2bdac8 connections UX 2024-11-28 14:59:19 +01:00
SPRINX0\prochazka
2283e91532 v5.5.7-beta.63 2024-11-27 18:30:05 +01:00
SPRINX0\prochazka
647894ad60 fix 2024-11-27 18:28:45 +01:00
SPRINX0\prochazka
574573abbb fix 2024-11-27 18:28:17 +01:00
SPRINX0\prochazka
a735a03cd7 fix 2024-11-27 18:27:11 +01:00
SPRINX0\prochazka
83881a0dac docker build fix 2024-11-27 18:26:05 +01:00
SPRINX0\prochazka
c04c6bbd2c v5.5.7-beta.62 2024-11-26 16:20:53 +01:00
SPRINX0\prochazka
42bbbc7ff4 fix job 2024-11-26 16:20:29 +01:00
SPRINX0\prochazka
1ecffeda71 default action improved & configurable 2024-11-26 15:19:39 +01:00
SPRINX0\prochazka
92992d1e95 ctx menu - open in new window 2024-11-26 14:19:20 +01:00
SPRINX0\prochazka
bc9df9750f single connection mode list handler 2024-11-26 12:47:36 +01:00
SPRINX0\prochazka
27e70e8031 new UX - fixed support for singledb connections 2024-11-26 12:29:16 +01:00
SPRINX0\prochazka
c823b8d19a UX 2024-11-26 09:30:37 +01:00
SPRINX0\prochazka
170ff77eec Merge branch 'feature/connection-keyboard-browse' 2024-11-26 09:11:23 +01:00
SPRINX0\prochazka
c241f5c562 focused DB UX 2024-11-26 09:04:13 +01:00
SPRINX0\prochazka
e06d964de4 connections UX WIP 2024-11-25 16:34:09 +01:00
SPRINX0\prochazka
dfdb86de6f db widget UX 2024-11-25 15:52:26 +01:00
SPRINX0\prochazka
a37b74f693 focusable databases WIP 2024-11-25 13:46:16 +01:00
SPRINX0\prochazka
398d9f15df focus connection or database WIP 2024-11-25 11:00:41 +01:00
SPRINX0\prochazka
ab7c2d7a31 set tab preview mode off in markTabUnsaved 2024-11-25 08:31:24 +01:00
Jan Prochazka
090549ff91 v5.5.7-beta.61 2024-11-22 16:20:00 +01:00
Jan Prochazka
10330c6597 Merge branch 'master' of github.com:dbgate/dbgate 2024-11-22 16:19:34 +01:00
Jan Prochazka
da2fe6a891 table & view preview mode switch 2024-11-22 16:19:29 +01:00
Jan Prochazka
01b88221c5 Merge pull request #945 from dbgate/feature-close-tab-hotkey-for-web
feat: add close tab hotkey for web
2024-11-22 15:26:43 +01:00
Nybkox
46d25710b8 feat: add close tab hotkey for web 2024-11-22 15:20:01 +01:00
Jan Prochazka
a40ec7e66b show all databases for filtered connections 2024-11-22 11:40:51 +01:00
Jan Prochazka
c8d2031d24 fix - don't call for DB list when searching in connections list 2024-11-22 11:25:46 +01:00
Jan Prochazka
4f838e0ae3 Merge branch 'feature/tab-preview-mode' 2024-11-22 10:43:24 +01:00
Jan Prochazka
c7cc1b7611 theme changes (hover bg, dark selection bg) 2024-11-22 10:22:38 +01:00
Jan Prochazka
bf67a5f13d UX 2024-11-22 10:15:43 +01:00
Jan Prochazka
e6bbe66873 use keyboard for navigation between searchbox and table list 2024-11-22 10:03:49 +01:00
Jan Prochazka
1a930acf0a tables keyboard navigation 2024-11-22 09:45:01 +01:00
Jan Prochazka
a497467137 fix 2024-11-22 08:45:30 +01:00
Jan Prochazka
b463416633 Merge branch 'master' into feature/tab-preview-mode 2024-11-22 08:35:28 +01:00
Jan Prochazka
ccf6240d65 Merge pull request #914 from dataspun/feature/geometry-autodetect-map
Update postgres plugin drivers.js
2024-11-22 08:28:40 +01:00
Jan Prochazka
5ccc12019d Merge pull request #943 from dbgate/feature-reopen-closed-tab
Feature reopen closed tab
2024-11-22 08:22:48 +01:00
Jan Prochazka
f57fa9aee9 Merge pull request #942 from dbgate/feature-prevent-spawning-same-modal
feat: prevent spawning the same modal if one instance is opened
2024-11-22 08:21:00 +01:00
Nybkox
80e841a43d feat: add reopen closed tab command 2024-11-22 02:19:41 +01:00
Nybkox
e1d759041d feat: prevent closing tab if any modal is open 2024-11-21 18:44:21 +01:00
SPRINX0\prochazka
fd6df055c0 focus tab by enter 2024-11-21 17:07:18 +01:00
SPRINX0\prochazka
669d0b9dac correctly focusing tabs 2024-11-21 16:53:46 +01:00
SPRINX0\prochazka
b9f9501e67 handle tab focus 2024-11-21 16:49:56 +01:00
SPRINX0\prochazka
4b1c021871 Revert "don't focus in tabs"
This reverts commit 90946c582d.
2024-11-21 16:12:27 +01:00
SPRINX0\prochazka
1f79627dbe change selected object when switching tab 2024-11-21 15:47:46 +01:00
SPRINX0\prochazka
dc18be07ce #938 current database is not changed after closing tab 2024-11-21 15:03:43 +01:00
Nybkox
83ac45f8cf feat: invalidate commands on modal show/close 2024-11-21 14:32:05 +01:00
SPRINX0\prochazka
c6cd865663 default action handling 2024-11-21 13:46:19 +01:00
Jan Prochazka
477636e0d7 Merge pull request #941 from dbgate/feature/word-wrap-option
feat: add word wrap option #823
2024-11-21 12:20:18 +01:00
Nybkox
77414ba934 feat: add word wrap option #823 2024-11-21 11:17:51 +01:00
SPRINX0\prochazka
86186072ed db app obj WIP 2024-11-20 17:12:54 +01:00
SPRINX0\prochazka
1216bcf9bf sql object tab refactor 2024-11-20 15:37:01 +01:00
SPRINX0\prochazka
788ea70d32 db app objc refactors 2024-11-20 15:30:47 +01:00
SPRINX0\prochazka
18de37c4e4 sql object tab 2024-11-20 14:53:06 +01:00
SPRINX0\prochazka
aeb81bd97f sql object tab - ability to show template 2024-11-20 14:33:05 +01:00
SPRINX0\prochazka
a68660f1ab sql object tab 2024-11-20 14:24:37 +01:00
SPRINX0\prochazka
5abfa85a0e script templates refactor 2024-11-20 13:51:18 +01:00
SPRINX0\prochazka
794f43d9ae call click when changing table by arrow 2024-11-20 11:25:07 +01:00
SPRINX0\prochazka
4b2f762200 v5.5.7-alpha.60 2024-11-20 10:19:40 +01:00
SPRINX0\prochazka
fc3664571b fixed resolving plugin 2024-11-20 10:18:54 +01:00
SPRINX0\prochazka
5db8f11fd6 dbappobj highlight 2024-11-20 08:16:13 +01:00
SPRINX0\prochazka
598674a7e0 show focus in data grid 2024-11-19 16:35:55 +01:00
SPRINX0\prochazka
af17eceb27 table keyboard navigation WIP 2024-11-19 15:54:18 +01:00
SPRINX0\prochazka
90946c582d don't focus in tabs 2024-11-19 14:13:58 +01:00
SPRINX0\prochazka
d619e0f961 tab preview mode - basic concept #767 2024-11-19 14:10:41 +01:00
SPRINX0\prochazka
08311145c8 docs 2024-11-19 13:04:00 +01:00
SPRINX0\prochazka
a80e37a208 maxMissingTablesRatio parameter 2024-11-19 12:55:42 +01:00
SPRINX0\prochazka
c88114cabe link to G2 2024-11-19 12:24:47 +01:00
SPRINX0\prochazka
e33f3a1492 rename view/procedure/function 2024-11-19 12:18:56 +01:00
SPRINX0\prochazka
8328fdad33 Merge branch 'master' of https://github.com/dbgate/dbgate 2024-11-19 10:35:14 +01:00
Jan Prochazka
8035380e7b commented handle autoincrement change 2024-11-19 10:34:49 +01:00
SPRINX0\prochazka
b4ea528643 fix 2024-11-19 10:32:09 +01:00
Jan Prochazka
b0012872fa force recreate table when changing autoincrement flag 2024-11-19 10:06:52 +01:00
SPRINX0\prochazka
274fb595a2 UX 2024-11-18 17:03:13 +01:00
SPRINX0\prochazka
c7ef4b9231 UX 2024-11-18 17:03:06 +01:00
Jan Prochazka
e64cfce423 fix test 2024-11-18 15:04:37 +01:00
Jan Prochazka
c0c9c7be20 mysql change column to not null 2024-11-18 14:57:02 +01:00
SPRINX0\prochazka
2ae98d0c2d Merge branch 'master' of https://github.com/dbgate/dbgate 2024-11-18 13:47:47 +01:00
SPRINX0\prochazka
a129834c16 fix 2024-11-18 13:47:42 +01:00
Jan Prochazka
71a9d6c5c0 fix 2024-11-18 13:47:23 +01:00
Jan Prochazka
1ce8f6bd1f set NOT NULL for column with default value 2024-11-18 13:41:29 +01:00
Jan Prochazka
85c4821606 added deploy test 2024-11-18 12:48:34 +01:00
Jan Prochazka
06ed9d7dfc fix 2024-11-18 12:40:53 +01:00
SPRINX0\prochazka
90de5edc99 v5.5.7-beta.59 2024-11-18 09:56:49 +01:00
SPRINX0\prochazka
72786e5dbb try to fix build 2024-11-18 09:56:38 +01:00
SPRINX0\prochazka
d92c08548b fix 2024-11-18 09:54:08 +01:00
SPRINX0\prochazka
b1893234c7 horizontal splitter improved 2024-11-18 09:25:58 +01:00
Jeremy
2c0b76fb3f Update drivers.js
add geometry to spatial types
2024-10-09 14:20:44 -07:00
305 changed files with 43575 additions and 3671 deletions

View File

@@ -1,83 +1,86 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: Electron app BETA
on:
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+'
jobs:
build:
runs-on: ${{ matrix.os }}
runs-on: '${{ matrix.os }}'
strategy:
fail-fast: false
matrix:
os: [macos-12, windows-2022, ubuntu-22.04]
# os: [macOS-10.15]
os:
- macos-14
- windows-2022
- ubuntu-22.04
steps:
- name: Install python 3.11 (MacOS)
if: matrix.os == 'macos-14'
run: |
brew install python@3.11
echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 18.x
- name: Use Node.js 22.x
uses: actions/setup-node@v1
with:
node-version: 18.x
- name: yarn adjustPackageJson
node-version: 22.x
- name: adjustPackageJson
run: |
yarn adjustPackageJson
node adjustPackageJson --community
- name: setUpdaterChannel beta
run: |
node setUpdaterChannel beta
- name: yarn set timeout
run: |
yarn config set network-timeout 100000
- name: yarn install
run: |
yarn install
- name: setCurrentVersion
run: |
yarn setCurrentVersion
- name: printSecrets
run: |
yarn printSecrets
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}'
- name: fillPackagedPlugins
run: |
yarn fillPackagedPlugins
- name: Install Snapcraft
if: matrix.os == 'ubuntu-22.04'
uses: samuelmeuli/action-snapcraft@v1
- name: Publish
run: |
yarn run build:app
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }} # token for electron publish
WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }}
# WIN_CSC_LINK: ${{ secrets.WINCERT_CERTIFICATE }}
# WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_PASSWORD }}
CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
- name: publishSnap
if: matrix.os == 'ubuntu-22.04'
run: |
snapcraft upload --release=beta app/dist/*.snap
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}}
GH_TOKEN: '${{ secrets.GH_TOKEN }}'
WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}'
WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}'
CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}'
CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}'
APPLE_ID: '${{ secrets.APPLE_ID }}'
APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}'
APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}'
SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}'
APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}'
- name: Copy artifacts
run: |
mkdir artifacts
@@ -89,8 +92,10 @@ jobs:
cp app/dist/*win*.exe artifacts/dbgate-beta.exe || true
cp app/dist/*win_x64.zip artifacts/dbgate-windows-beta.zip || true
cp app/dist/*win_arm64.zip artifacts/dbgate-windows-beta-arm64.zip || true
cp app/dist/*-mac_x64.dmg artifacts/dbgate-beta.dmg || true
cp app/dist/*-mac_universal.dmg artifacts/dbgate-beta.dmg || true
cp app/dist/*-mac_x64.dmg artifacts/dbgate-beta-x64.dmg || true
cp app/dist/*-mac_arm64.dmg artifacts/dbgate-beta-arm64.dmg || true
mv app/dist/*.snap artifacts/dbgate-beta.snap || true
mv app/dist/*.exe artifacts/ || true
mv app/dist/*.zip artifacts/ || true
@@ -103,18 +108,21 @@ jobs:
mv app/dist/*.yml artifacts/ || true
rm artifacts/builder-debug.yml
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }}
name: '${{ matrix.os }}'
path: artifacts
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
if: 'startsWith(github.ref, ''refs/tags/'')'
with:
files: 'artifacts/**'
files: artifacts/**
prerelease: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
- name: Print content of notarization-error.log
if: failure() && matrix.os == 'macos-14'
run: |
find . -type f -name "notarization-error.log" -exec echo "=== Start of {} ===" \; -exec cat {} \; -exec echo "=== End of {} ===" \;

View File

@@ -1,43 +1,45 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: Electron app PREMIUM BETA
on:
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+'
jobs:
build:
runs-on: ${{ matrix.os }}
runs-on: '${{ matrix.os }}'
strategy:
fail-fast: false
matrix:
# os: [windows-2022]
# os: [ubuntu-22.04]
# os: [windows-2022, ubuntu-22.04]
os: [macos-12, windows-2022, ubuntu-22.04]
# os: [macOS-10.15]
os:
- macos-14
- windows-2022
- ubuntu-22.04
steps:
- name: Install python 3.11 (MacOS)
if: matrix.os == 'macos-14'
run: |
brew install python@3.11
echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 18.x
- name: Use Node.js 22.x
uses: actions/setup-node@v1
with:
node-version: 18.x
node-version: 22.x
- name: Checkout dbgate/dbgate-pro
uses: actions/checkout@v2
with:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
token: '${{ secrets.GH_TOKEN }}'
path: dbgate-pro
ref: ef8978facad7372157c7a5e367763ecc7a07a14a
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
@@ -49,76 +51,82 @@ jobs:
yarn
node sync.js --nowatch
cd ..
- name: adjustPackageJson
run: |
cd ..
cd dbgate-merged
- name: yarn adjustPackageJson
run: |
cd ..
cd dbgate-merged
yarn adjustPackageJson
- name: adjustAppPackageJsonPremium
run: |
cd ..
cd dbgate-merged
node adjustAppPackageJsonPremium
node adjustPackageJson --premium
- name: setUpdaterChannel premium-beta
run: |
cd ..
cd dbgate-merged
node setUpdaterChannel premium-beta
- name: yarn set timeout
run: |
cd ..
cd dbgate-merged
yarn config set network-timeout 100000
- name: yarn install
run: |
cd ..
cd dbgate-merged
yarn install
- name: setCurrentVersion
run: |
cd ..
cd dbgate-merged
yarn setCurrentVersion
- name: printSecrets
run: |
cd ..
cd dbgate-merged
yarn printSecrets
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}'
- name: fillPackagedPlugins
run: |
cd ..
cd dbgate-merged
yarn fillPackagedPlugins
- name: Publish
run: |
cd ..
cd dbgate-merged
yarn run build:app
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }} # token for electron publish
WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }}
# WIN_CSC_LINK: ${{ secrets.WINCERT_CERTIFICATE }}
# WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_PASSWORD }}
CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
GH_TOKEN: '${{ secrets.GH_TOKEN }}'
WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}'
WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}'
CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}'
CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}'
APPLE_ID: '${{ secrets.APPLE_ID }}'
APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}'
APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}'
SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}'
APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}'
- name: Copy artifacts
run: |
mkdir artifacts
cp ../dbgate-merged/app/dist/*.deb artifacts/dbgate-premium-beta.deb || true
cp ../dbgate-merged/app/dist/*x86*.AppImage artifacts/dbgate-premium-beta.AppImage || true
cp ../dbgate-merged/app/dist/*arm64*.AppImage artifacts/dbgate-premium-beta-arm64.AppImage || true
cp ../dbgate-merged/app/dist/*armv7l*.AppImage artifacts/dbgate-premium-beta-armv7l.AppImage || true
cp ../dbgate-merged/app/dist/*win*.exe artifacts/dbgate-premium-beta.exe || true
cp ../dbgate-merged/app/dist/*-mac_x64.dmg artifacts/dbgate-premium-beta.dmg || true
cp ../dbgate-merged/app/dist/*win_x64.zip artifacts/dbgate-windows-premium-beta.zip || true
cp ../dbgate-merged/app/dist/*win_arm64.zip artifacts/dbgate-windows-premium-beta-arm64.zip || true
cp ../dbgate-merged/app/dist/*-mac_universal.dmg artifacts/dbgate-premium-beta.dmg || true
cp ../dbgate-merged/app/dist/*-mac_x64.dmg artifacts/dbgate-premium-beta-x64.dmg || true
cp ../dbgate-merged/app/dist/*-mac_arm64.dmg artifacts/dbgate-premium-beta-arm64.dmg || true
mv ../dbgate-merged/app/dist/*.snap artifacts/dbgate-premium-beta.snap || true
mv ../dbgate-merged/app/dist/*.exe artifacts/ || true
mv ../dbgate-merged/app/dist/*.zip artifacts/ || true
@@ -131,18 +139,23 @@ jobs:
mv ../dbgate-merged/app/dist/*.yml artifacts/ || true
rm artifacts/builder-debug.yml
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }}
name: '${{ matrix.os }}'
path: artifacts
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
if: 'startsWith(github.ref, ''refs/tags/'')'
with:
files: 'artifacts/**'
files: artifacts/**
prerelease: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
- name: Print content of notarization-error.log
if: failure() && matrix.os == 'macos-14'
run: |
cd ..
cd dbgate-merged
find . -type f -name "notarization-error.log" -exec echo "=== Start of {} ===" \; -exec cat {} \; -exec echo "=== End of {} ===" \;

View File

@@ -1,44 +1,45 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: Electron app PREMIUM
on:
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
# - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
# branches:
# - production
jobs:
build:
runs-on: ${{ matrix.os }}
runs-on: '${{ matrix.os }}'
strategy:
fail-fast: false
matrix:
# os: [ubuntu-22.04, windows-2016]
os: [macos-12, windows-2022, ubuntu-22.04]
os:
- macos-14
- windows-2022
- ubuntu-22.04
steps:
- name: Install python 3.11 (MacOS)
if: matrix.os == 'macos-14'
run: |
brew install python@3.11
echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 18.x
- name: Use Node.js 22.x
uses: actions/setup-node@v1
with:
node-version: 18.x
node-version: 22.x
- name: Checkout dbgate/dbgate-pro
uses: actions/checkout@v2
with:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
token: '${{ secrets.GH_TOKEN }}'
path: dbgate-pro
ref: ef8978facad7372157c7a5e367763ecc7a07a14a
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
@@ -50,101 +51,111 @@ jobs:
yarn
node sync.js --nowatch
cd ..
- name: adjustPackageJson
run: |
cd ..
cd dbgate-merged
- name: yarn adjustPackageJson
run: |
cd ..
cd dbgate-merged
yarn adjustPackageJson
- name: adjustAppPackageJsonPremium
run: |
cd ..
cd dbgate-merged
node adjustAppPackageJsonPremium
node adjustPackageJson --premium
- name: setUpdaterChannel premium
run: |
cd ..
cd dbgate-merged
node setUpdaterChannel premium
- name: yarn set timeout
run: |
cd ..
cd dbgate-merged
yarn config set network-timeout 100000
- name: yarn install
run: |
cd ..
cd dbgate-merged
yarn install
- name: setCurrentVersion
run: |
cd ..
cd dbgate-merged
yarn setCurrentVersion
- name: printSecrets
run: |
cd ..
cd dbgate-merged
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}'
- name: fillPackagedPlugins
run: |
cd ..
cd dbgate-merged
yarn fillPackagedPlugins
- name: Publish
run: |
cd ..
cd dbgate-merged
yarn run build:app
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }} # token for electron publish
WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }}
# WIN_CSC_LINK: ${{ secrets.WINCERT_CERTIFICATE }}
# WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_PASSWORD }}
CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
GH_TOKEN: '${{ secrets.GH_TOKEN }}'
WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}'
WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}'
CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}'
CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}'
APPLE_ID: '${{ secrets.APPLE_ID }}'
APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}'
APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}'
SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}'
APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}'
- name: Copy artifacts
run: |
mkdir artifacts
cp ../dbgate-merged/app/dist/*.deb artifacts/dbgate-premium-latest.deb || true
cp ../dbgate-merged/app/dist/*x86*.AppImage artifacts/dbgate-premium-latest.AppImage || true
cp ../dbgate-merged/app/dist/*.exe artifacts/dbgate-premium-latest.exe || true
cp ../dbgate-merged/app/dist/*win_x64.zip artifacts/dbgate-premium-windows-latest.zip || true
cp ../dbgate-merged/app/dist/*win_arm64.zip artifacts/dbgate-premium-windows-latest-arm64.zip || true
cp ../dbgate-merged/app/dist/*arm64*.AppImage artifacts/dbgate-premium-latest-arm64.AppImage || true
cp ../dbgate-merged/app/dist/*armv7l*.AppImage artifacts/dbgate-premium-latest-armv7l.AppImage || true
cp ../dbgate-merged/app/dist/*win*.exe artifacts/dbgate-premium-latest.exe || true
cp ../dbgate-merged/app/dist/*win_x64.zip artifacts/dbgate-windows-premium-latest.zip || true
cp ../dbgate-merged/app/dist/*win_arm64.zip artifacts/dbgate-windows-premium-latest-arm64.zip || true
cp ../dbgate-merged/app/dist/*-mac_universal.dmg artifacts/dbgate-premium-latest.dmg || true
cp ../dbgate-merged/app/dist/*-mac_x64.dmg artifacts/dbgate-premium-latest-x64.dmg || true
cp ../dbgate-merged/app/dist/*-mac_arm64.dmg artifacts/dbgate-premium-latest-arm64.dmg || true
mv ../dbgate-merged/app/dist/*.snap artifacts/dbgate-premium-latest.snap || true
mv ../dbgate-merged/app/dist/*.exe artifacts/ || true
mv ../dbgate-merged/app/dist/*.zip artifacts/ || true
mv ../dbgate-merged/app/dist/*.tar.gz artifacts/ || true
mv ../dbgate-merged/app/dist/*.AppImage artifacts/ || true
mv ../dbgate-merged/app/dist/*.deb artifacts/ || true
mv ../dbgate-merged/app/dist/*.snap artifacts/ || true
mv ../dbgate-merged/app/dist/*.dmg artifacts/ || true
mv ../dbgate-merged/app/dist/*.blockmap artifacts/ || true
mv ../dbgate-merged/app/dist/*.yml artifacts/ || true
rm artifacts/builder-debug.yml
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }}
name: '${{ matrix.os }}'
path: artifacts
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
if: 'startsWith(github.ref, ''refs/tags/'')'
with:
files: 'artifacts/**'
files: artifacts/**
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
- name: Print content of notarization-error.log
if: failure() && matrix.os == 'macos-14'
run: |
cd ..
cd dbgate-merged
find . -type f -name "notarization-error.log" -exec echo "=== Start of {} ===" \; -exec cat {} \; -exec echo "=== End of {} ===" \;

View File

@@ -1,90 +1,85 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: Electron app
on:
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
# - 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
# branches:
# - production
jobs:
build:
runs-on: ${{ matrix.os }}
runs-on: '${{ matrix.os }}'
strategy:
fail-fast: false
matrix:
# os: [ubuntu-22.04, windows-2016]
os: [macos-12, windows-2022, ubuntu-22.04]
os:
- macos-14
- windows-2022
- ubuntu-22.04
steps:
- name: Install python 3.11 (MacOS)
if: matrix.os == 'macos-14'
run: |
brew install python@3.11
echo "PYTHON=/opt/homebrew/bin/python3.11" >> $GITHUB_ENV
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 18.x
- name: Use Node.js 22.x
uses: actions/setup-node@v1
with:
node-version: 18.x
- name: yarn adjustPackageJson
node-version: 22.x
- name: adjustPackageJson
run: |
yarn adjustPackageJson
node adjustPackageJson --community
- name: yarn set timeout
run: |
yarn config set network-timeout 100000
- name: yarn install
run: |
# yarn --version
# yarn config set network-timeout 300000
yarn install
- name: setCurrentVersion
run: |
yarn setCurrentVersion
- name: printSecrets
run: |
yarn printSecrets
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}'
- name: fillPackagedPlugins
run: |
yarn fillPackagedPlugins
- name: Install Snapcraft
if: matrix.os == 'ubuntu-22.04'
uses: samuelmeuli/action-snapcraft@v1
- name: Publish
run: |
yarn run build:app
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }} # token for electron publish
WIN_CSC_LINK: ${{ secrets.WINCERT_2025 }}
WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_2025_PASSWORD }}
# WIN_CSC_LINK: ${{ secrets.WINCERT_CERTIFICATE }}
# WIN_CSC_KEY_PASSWORD: ${{ secrets.WINCERT_PASSWORD }}
CSC_LINK: ${{ secrets.APPLECERT_CERTIFICATE }}
CSC_KEY_PASSWORD: ${{ secrets.APPLECERT_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
GH_TOKEN: '${{ secrets.GH_TOKEN }}'
WIN_CSC_LINK: '${{ secrets.WINCERT_2025 }}'
WIN_CSC_KEY_PASSWORD: '${{ secrets.WINCERT_2025_PASSWORD }}'
CSC_LINK: '${{ secrets.APPLECERT_CERTIFICATE }}'
CSC_KEY_PASSWORD: '${{ secrets.APPLECERT_PASSWORD }}'
APPLE_ID: '${{ secrets.APPLE_ID }}'
APPLE_TEAM_ID: '${{ secrets.APPLE_TEAM_ID }}'
APPLE_ID_PASSWORD: '${{ secrets.APPLE_ID_PASSWORD }}'
SNAPCRAFT_STORE_CREDENTIALS: '${{secrets.SNAPCRAFT_LOGIN}}'
APPLE_APP_SPECIFIC_PASSWORD: '${{secrets.APPLE_APP_SPECIFIC_PASSWORD}}'
- name: generatePadFile
run: |
yarn generatePadFile
- name: publishSnap
if: matrix.os == 'ubuntu-22.04'
run: |
snapcraft upload --release=stable app/dist/*.snap
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{secrets.SNAPCRAFT_LOGIN}}
- name: Copy artifacts
run: |
mkdir artifacts
@@ -93,74 +88,44 @@ jobs:
cp app/dist/*x86*.AppImage artifacts/dbgate-latest.AppImage || true
cp app/dist/*arm64*.AppImage artifacts/dbgate-latest-arm64.AppImage || true
cp app/dist/*armv7l*.AppImage artifacts/dbgate-latest-armv7l.AppImage || true
cp app/dist/*.exe artifacts/dbgate-latest.exe || true
cp app/dist/*win*.exe artifacts/dbgate-latest.exe || true
cp app/dist/*win_x64.zip artifacts/dbgate-windows-latest.zip || true
cp app/dist/*win_arm64.zip artifacts/dbgate-windows-latest-arm64.zip || true
cp app/dist/*-mac_universal.dmg artifacts/dbgate-latest.dmg || true
cp app/dist/*-mac_x64.dmg artifacts/dbgate-latest-x64.dmg || true
cp app/dist/*-mac_arm64.dmg artifacts/dbgate-latest-arm64.dmg || true
mv app/dist/*.snap artifacts/dbgate-latest.snap || true
mv app/dist/*.exe artifacts/ || true
mv app/dist/*.zip artifacts/ || true
mv app/dist/*.tar.gz artifacts/ || true
mv app/dist/*.AppImage artifacts/ || true
mv app/dist/*.deb artifacts/ || true
mv app/dist/*.snap artifacts/ || true
mv app/dist/*.dmg artifacts/ || true
mv app/dist/*.snap artifacts/dbgate-latest.snap || true
mv app/dist/*.blockmap artifacts/ || true
mv app/dist/*.yml artifacts/ || true
rm artifacts/builder-debug.yml
# - name: Copy artifacts Linux, MacOs
# if: matrix.os != 'windows-2016'
# run: |
# mkdir artifacts
# cp app/dist/*.AppImage artifacts/ || true
# cp app/dist/*.dmg artifacts/ || true
# cp app/dist/*.deb artifacts/ || true
# mv app/dist/*.deb artifacts/dbgate-linux.deb || true
# mv app/dist/*.AppImage artifacts/dbgate-linux.AppImage || true
# mv app/dist/*.dmg artifacts/dbgate-mac.dmg || true
# - name: Copy artifacts Win
# if: matrix.os == 'windows-2016'
# run: |
# mkdir artifacts
# cp app/dist/*.exe artifacts/ || true
# mv app/dist/*.exe artifacts/dbgate-windows.exe
# mv app/dist/latest.yml artifacts/latest.yml || true
- name: Copy PAD file
if: matrix.os == 'windows-2022'
run: |
mv app/dist/dbgate-pad.xml artifacts/ || true
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.os }}
name: '${{ matrix.os }}'
path: artifacts
- name: Release
uses: softprops/action-gh-release@v1
if: startsWith(github.ref, 'refs/tags/')
if: 'startsWith(github.ref, ''refs/tags/'')'
with:
files: 'artifacts/**'
files: artifacts/**
prerelease: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
- name: Print content of notarization-error.log
if: failure() && matrix.os == 'macos-14'
run: |
# - name: Create Release
# id: create_release
# uses: actions/create-release@v1
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# with:
# tag_name: ${{ github.ref }}
# release_name: Release ${{ github.ref }}
# draft: false
# prerelease: false
find . -type f -name "notarization-error.log" -exec echo "=== Start of {} ===" \; -exec cat {} \; -exec echo "=== End of {} ===" \;

123
.github/workflows/build-aws-pro.yaml vendored Normal file
View File

@@ -0,0 +1,123 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: AWS image PREMIUM
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-packer-beta.[0-9]+'
jobs:
build:
runs-on: '${{ matrix.os }}'
strategy:
matrix:
os:
- ubuntu-22.04
steps:
- name: Context
env:
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Use Node.js 18.x
uses: actions/setup-node@v1
with:
node-version: 18.x
- name: Setup `packer`
uses: hashicorp/setup-packer@main
with:
version: latest
- name: Checkout dbgate/dbgate-pro
uses: actions/checkout@v2
with:
repository: dbgate/dbgate-pro
token: '${{ secrets.GH_TOKEN }}'
path: dbgate-pro
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
mv dbgate-pro/* ../dbgate-pro/
cd ..
mkdir dbgate-merged
cd dbgate-pro
cd sync
yarn
node sync.js --nowatch
cd ..
- name: adjustPackageJson
run: |
cd ..
cd dbgate-merged
node adjustPackageJson --premium
- name: yarn install
run: |
cd ..
cd dbgate-merged
yarn install
- name: setCurrentVersion
run: |
cd ..
cd dbgate-merged
yarn setCurrentVersion
- name: printSecrets
run: |
cd ..
cd dbgate-merged
yarn printSecrets
env:
GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}'
- name: Prepare packer build
run: |
cd ..
cd dbgate-merged
yarn run prepare:packer
cd packer
zip -r cloud-build.zip build
- name: Copy artifacts
run: |
mkdir artifacts
cp ../dbgate-merged/packer/cloud-build.zip artifacts/cloud-build.zip || true
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: '${{ matrix.os }}'
path: artifacts
- name: Release
uses: softprops/action-gh-release@v1
if: 'startsWith(github.ref, ''refs/tags/'')'
with:
files: artifacts/**
prerelease: true
env:
GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
- name: Run `packer init`
run: |
cd ../dbgate-merged/packer
packer init ./aws-ubuntu.pkr.hcl
env:
AWS_ACCESS_KEY_ID: '${{secrets.AWS_ACCESS_KEY_ID}}'
AWS_SECRET_ACCESS_KEY: '${{secrets.AWS_SECRET_ACCESS_KEY}}'
AWS_DEFAULT_REGION: '${{secrets.AWS_DEFAULT_REGION}}'
- name: Run `packer build`
run: |
cd ../dbgate-merged/packer
packer build ./aws-ubuntu.pkr.hcl
env:
AWS_ACCESS_KEY_ID: '${{secrets.AWS_ACCESS_KEY_ID}}'
AWS_SECRET_ACCESS_KEY: '${{secrets.AWS_SECRET_ACCESS_KEY}}'
AWS_DEFAULT_REGION: '${{secrets.AWS_DEFAULT_REGION}}'
- name: Install jq
run: |
sudo apt-get install jq -y
- name: Delete old AMIs
run: |
cd ../dbgate-merged/packer
chmod +x delete-old-amis.sh
./delete-old-amis.sh
env:
AWS_ACCESS_KEY_ID: '${{secrets.AWS_ACCESS_KEY_ID}}'
AWS_SECRET_ACCESS_KEY: '${{secrets.AWS_SECRET_ACCESS_KEY}}'
AWS_DEFAULT_REGION: '${{secrets.AWS_DEFAULT_REGION}}'

View File

@@ -1,35 +1,32 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: Docker image PREMIUM
on:
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-premium-beta.[0-9]+'
jobs:
build:
runs-on: ${{ matrix.os }}
runs-on: '${{ matrix.os }}'
strategy:
matrix:
os: [ubuntu-22.04]
os:
- ubuntu-22.04
steps:
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
dbgate/dbgate-premium
images: dbgate/dbgate-premium
flavor: |
latest=false
tags: |
@@ -37,19 +34,17 @@ jobs:
type=match,pattern=\d+.\d+.\d+,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
type=raw,value=latest,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
- name: Use Node.js 18.x
uses: actions/setup-node@v1
with:
node-version: 18.x
- name: Checkout dbgate/dbgate-pro
uses: actions/checkout@v2
with:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
token: '${{ secrets.GH_TOKEN }}'
path: dbgate-pro
ref: ef8978facad7372157c7a5e367763ecc7a07a14a
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
@@ -61,50 +56,51 @@ jobs:
yarn
node sync.js --nowatch
cd ..
- name: yarn adjustPackageJson
- name: adjustPackageJson
run: |
cd ..
cd dbgate-merged
yarn adjustPackageJson
node adjustPackageJson --premium
- name: yarn install
run: |
cd ..
cd dbgate-merged
yarn install
# yarn --version
# yarn config set network-timeout 300000
yarn install
- name: setCurrentVersion
run: |
cd ..
cd dbgate-merged
yarn setCurrentVersion
- name: printSecrets
run: |
cd ..
cd dbgate-merged
yarn printSecrets
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}'
- name: Prepare docker image
run: |
cd ..
cd dbgate-merged
yarn run prepare:docker
yarn run prepare:docker
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
username: '${{ secrets.DOCKER_USERNAME }}'
password: '${{ secrets.DOCKER_PASSWORD }}'
- name: Build and push
uses: docker/build-push-action@v3
with:
push: true
context: ../dbgate-merged/docker
tags: ${{ steps.meta.outputs.tags }}
platforms: linux/amd64,linux/arm64
tags: '${{ steps.meta.outputs.tags }}'
platforms: 'linux/amd64,linux/arm64'

View File

@@ -1,35 +1,32 @@
name: Docker image
on:
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: Docker image Community
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+'
jobs:
build:
runs-on: ${{ matrix.os }}
runs-on: '${{ matrix.os }}'
strategy:
matrix:
os: [ubuntu-22.04]
os:
- ubuntu-22.04
steps:
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
fetch-depth: 1
- name: Docker meta
id: meta
uses: docker/metadata-action@v4
with:
images: |
dbgate/dbgate
images: dbgate/dbgate
flavor: |
latest=false
tags: |
@@ -37,7 +34,6 @@ jobs:
type=match,pattern=\d+.\d+.\d+,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
type=raw,value=latest,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
- name: Docker alpine meta
id: alpmeta
uses: docker/metadata-action@v4
@@ -51,56 +47,53 @@ jobs:
type=match,pattern=\d+.\d+.\d+,suffix=-alpine,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
type=raw,value=alpine,enable=${{ !contains(github.ref_name, '-docker.') && !contains(github.ref_name, '-beta.') }}
- name: Use Node.js 18.x
uses: actions/setup-node@v1
with:
node-version: 18.x
- name: yarn adjustPackageJson
- name: adjustPackageJson
run: |
yarn adjustPackageJson
node adjustPackageJson --community
- name: yarn install
run: |
# yarn --version
# yarn config set network-timeout 300000
yarn install
- name: setCurrentVersion
run: |
yarn setCurrentVersion
- name: printSecrets
run: |
yarn printSecrets
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}'
- name: Prepare docker image
run: |
yarn run prepare:docker
yarn run prepare:docker
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
username: '${{ secrets.DOCKER_USERNAME }}'
password: '${{ secrets.DOCKER_PASSWORD }}'
- name: Build and push
uses: docker/build-push-action@v3
with:
push: true
context: ./docker
tags: ${{ steps.meta.outputs.tags }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
tags: '${{ steps.meta.outputs.tags }}'
platforms: 'linux/amd64,linux/arm64,linux/arm/v7'
- name: Build and push alpine
uses: docker/build-push-action@v3
with:
push: true
context: ./docker
file: ./docker/Dockerfile-alpine
tags: ${{ steps.alpmeta.outputs.tags }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
tags: '${{ steps.alpmeta.outputs.tags }}'
platforms: 'linux/amd64,linux/arm64,linux/arm/v7'

View File

@@ -1,31 +1,23 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: NPM packages PREMIUM
# on: [push]
on:
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+'
# on:
# push:
# branches:
# - production
jobs:
build:
runs-on: ${{ matrix.os }}
runs-on: '${{ matrix.os }}'
strategy:
matrix:
os: [ubuntu-22.04]
os:
- ubuntu-22.04
steps:
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
@@ -34,14 +26,13 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: 18.x
- name: Checkout dbgate/dbgate-pro
uses: actions/checkout@v2
with:
repository: dbgate/dbgate-pro
token: ${{ secrets.GH_TOKEN }}
token: '${{ secrets.GH_TOKEN }}'
path: dbgate-pro
ref: ef8978facad7372157c7a5e367763ecc7a07a14a
- name: Merge dbgate/dbgate-pro
run: |
mkdir ../dbgate-pro
@@ -53,59 +44,55 @@ jobs:
yarn
node sync.js --nowatch
cd ..
- name: adjustNpmPackageJsonPremium
run: |
cd ..
cd dbgate-merged
node adjustNpmPackageJsonPremium
- name: Configure NPM token
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: '${{ secrets.NPM_TOKEN }}'
run: |
cd ..
cd dbgate-merged
npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}"
- name: Remove dbmodel - should be not published
run: |
cd ..
cd dbgate-merged
rm -rf packages/dbmodel
- name: yarn install
run: |
cd ..
cd dbgate-merged
yarn install
- name: setCurrentVersion
run: |
cd ..
cd dbgate-merged
yarn setCurrentVersion
- name: printSecrets
run: |
cd ..
cd dbgate-merged
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}'
- name: Publish dbgate-api-premium
run: |
cd ..
cd dbgate-merged/packages/api
npm publish
- name: Publish dbgate-web-premium
run: |
cd ..
cd dbgate-merged/packages/web
npm publish
- name: Publish dbgate-serve-premium
run: |
cd ..
cd dbgate-merged/packages/serve
npm publish
- name: Publish dbgate-plugin-cosmosdb
run: |
cd ..

View File

@@ -1,31 +1,23 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: NPM packages
# on: [push]
on:
'on':
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-alpha.[0-9]+'
# on:
# push:
# branches:
# - production
jobs:
build:
runs-on: ${{ matrix.os }}
runs-on: '${{ matrix.os }}'
strategy:
matrix:
os: [ubuntu-22.04]
os:
- ubuntu-22.04
steps:
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
GITHUB_CONTEXT: '${{ toJson(github) }}'
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
with:
@@ -34,37 +26,30 @@ jobs:
uses: actions/setup-node@v1
with:
node-version: 18.x
- name: Configure NPM token
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NPM_TOKEN: '${{ secrets.NPM_TOKEN }}'
run: |
npm config set '//registry.npmjs.org/:_authToken' "${NPM_TOKEN}"
- name: yarn install
run: |
yarn install
- name: setCurrentVersion
run: |
yarn setCurrentVersion
- name: printSecrets
run: |
yarn printSecrets
yarn printSecrets
env:
GIST_UPLOAD_SECRET : ${{secrets.GIST_UPLOAD_SECRET}}
GIST_UPLOAD_SECRET: '${{secrets.GIST_UPLOAD_SECRET}}'
- name: Publish types
working-directory: packages/types
run: |
npm publish
- name: Publish tools
working-directory: packages/tools
run: |
npm publish
- name: Publish sqltree
working-directory: packages/sqltree
run: |
@@ -74,82 +59,66 @@ jobs:
working-directory: packages/api
run: |
npm publish
- name: Publish datalib
working-directory: packages/datalib
run: |
npm publish
- name: Publish filterparser
working-directory: packages/filterparser
run: |
npm publish
- name: Publish web
working-directory: packages/web
run: |
npm publish
- name: Publish dbgate-serve
working-directory: packages/serve
run: |
npm publish
- name: Publish dbmodel
working-directory: packages/dbmodel
run: |
npm publish
- name: Publish dbgate-plugin-csv
working-directory: plugins/dbgate-plugin-csv
run: |
npm publish
- name: Publish dbgate-plugin-xml
working-directory: plugins/dbgate-plugin-xml
run: |
npm publish
- name: Publish dbgate-plugin-excel
working-directory: plugins/dbgate-plugin-excel
run: |
npm publish
- name: Publish dbgate-plugin-mssql
working-directory: plugins/dbgate-plugin-mssql
run: |
npm publish
- name: Publish dbgate-plugin-mysql
working-directory: plugins/dbgate-plugin-mysql
run: |
npm publish
- name: Publish dbgate-plugin-mongo
working-directory: plugins/dbgate-plugin-mongo
run: |
npm publish
- name: Publish dbgate-plugin-postgres
working-directory: plugins/dbgate-plugin-postgres
run: |
npm publish
- name: Publish dbgate-plugin-sqlite
working-directory: plugins/dbgate-plugin-sqlite
run: |
npm publish
- name: Publish dbgate-plugin-redis
working-directory: plugins/dbgate-plugin-redis
run: |
npm publish
- name: Publish dbgate-plugin-oracle
working-directory: plugins/dbgate-plugin-oracle
run: |
npm publish
- name: Publish dbgate-plugin-clickhouse
working-directory: plugins/dbgate-plugin-clickhouse
run: |

View File

@@ -0,0 +1,45 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: Build test containers
'on':
push:
branches:
- master
- develop
- feature/**
paths:
- e2e-tests/containers/**
jobs:
build-docker-ssh:
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v3
- name: Build mysql-ssh-login image
run: |
docker build -t dbgate/mysql-ssh-login:latest e2e-tests/containers/mysql-ssh-login
- name: Build mysql-ssh-keyfile image
run: |
docker build -t dbgate/mysql-ssh-keyfile:latest e2e-tests/containers/mysql-ssh-keyfile
- name: Build dex image
run: |
docker build -t dbgate/dex:latest e2e-tests/containers/dex
- name: Log in to GHCR
uses: docker/login-action@v2
with:
registry: ghcr.io
username: '${{ github.actor }}'
password: '${{ secrets.GITHUB_TOKEN }}'
- name: Push mysql-ssh-login to GHCR
run: |
docker tag dbgate/mysql-ssh-login:latest ghcr.io/dbgate/mysql-ssh-login:latest
docker push ghcr.io/dbgate/mysql-ssh-login:latest
- name: Push mysql-ssh-keyfile to GHCR
run: |
docker tag dbgate/mysql-ssh-keyfile:latest ghcr.io/dbgate/mysql-ssh-keyfile:latest
docker push ghcr.io/dbgate/mysql-ssh-keyfile:latest
- name: Push dex to GHCR
run: |
docker tag dbgate/dex:latest ghcr.io/dbgate/dex:latest
docker push ghcr.io/dbgate/dex:latest

View File

@@ -1,32 +1,42 @@
# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
name: Run tests
on:
'on':
push:
branches:
- master
- develop
- 'feature/**'
- feature/**
jobs:
test-runner:
test:
runs-on: ubuntu-latest
container: node:18
steps:
- name: Context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- uses: actions/checkout@v2
- name: Use Node.js 18.x
uses: actions/setup-node@v1
with:
node-version: 18.x
- uses: actions/checkout@v3
with:
fetch-depth: 1
- name: yarn install
run: |
yarn install
- name: Build packer dist for cypress
run: |
yarn prepare:packer
- name: yarn install cypress
run: |
cd e2e-tests
yarn install
- name: Run Cypress tests
run: |
cd e2e-tests
yarn test:ci
- name: Integration tests
run: |
cd integration-tests
yarn test:ci
# yarn wait:ci
- name: Filter parser tests
if: always()
run: |
@@ -40,49 +50,77 @@ jobs:
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
github-token: '${{ secrets.GITHUB_TOKEN }}'
result-file: integration-tests/result.json
action-name: Integration tests
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
github-token: '${{ secrets.GITHUB_TOKEN }}'
result-file: packages/filterparser/result.json
action-name: Filter parser test results
- uses: tanmen/jest-reporter@v1
if: always()
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
github-token: '${{ secrets.GITHUB_TOKEN }}'
result-file: packages/datalib/result.json
action-name: Datalib (perspectives) test results
services:
postgres:
postgres-integr:
image: postgres
env:
POSTGRES_PASSWORD: Pwd2020Db
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
mysql:
image: mysql:8.0.18
options: '--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5'
ports:
- '15000:5432'
mysql-integr:
image: 'mysql:8.0.18'
env:
MYSQL_ROOT_PASSWORD: Pwd2020Db
mssql:
ports:
- '15001:3306'
mssql-integr:
image: mcr.microsoft.com/mssql/server
env:
ACCEPT_EULA: Y
ACCEPT_EULA: 'Y'
SA_PASSWORD: Pwd2020Db
MSSQL_PID: Express
clickhouse:
image: bitnami/clickhouse:24.8.4
ports:
- '15002:1433'
clickhouse-integr:
image: 'bitnami/clickhouse:24.8.4'
env:
CLICKHOUSE_ADMIN_PASSWORD: Pwd2020Db
# cockroachdb:
# image: cockroachdb/cockroach
ports:
- '15005:8123'
oracle-integr:
image: 'gvenzl/oracle-xe:21-slim'
env:
ORACLE_PASSWORD: Pwd2020Db
ports:
- '15006:1521'
postgres-cypress:
image: postgres
options: '--health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5'
env:
POSTGRES_PASSWORD: Pwd2020Db
ports:
- '16000:5432'
mysql-cypress:
image: 'mysql:8.0.18'
ports:
- '16004:3306'
env:
MYSQL_ROOT_PASSWORD: Pwd2020Db
mysql-ssh-login:
image: 'ghcr.io/dbgate/mysql-ssh-login:latest'
ports:
- '16006:22'
mysql-ssh-keyfile:
image: 'ghcr.io/dbgate/mysql-ssh-keyfile:latest'
ports:
- '16008:22'
dex:
image: 'ghcr.io/dbgate/dex:latest'
ports:
- '16009:5556'

1
.nvmrc Normal file
View File

@@ -0,0 +1 @@
v21.7.3

View File

@@ -8,11 +8,93 @@ Builds:
- linux - application for linux
- win - application for Windows
### Not published
### 6.1.6
- FIXED: Hotfix build process for premium edition
### 6.1.5
- FIXED: Serious security hotfix (for Docker and NPM, when using LOGIN and PASSWORD environment variables or LOGIN_PASSWORD_xxx)
- no changes for desktop app and for Team premium edition, when using storage DB
### 6.1.4
- CHANGED: Show Data/Structure button in one place #1015
- ADDED: Data view coloring (every second row) #1014
- ADDED: Pin icon for tab in preview mode (#1013)
- FIXED: Pin icon misplaced #1007
- ADDED: Set client name when connecting to redis #1004
- ADDED: Redis loading keys optimalization #1002
- ADDED: Browse redis keys with preview with keyboard
- FIXED: Cannot expand tables and views returned from search #1000
- ADDED: Expand all/Collapse all/Expand document commands in MongoDB JSON view #976
- ADDED: Configurable page size for MongoDB collection #976
- ADDED: Redis - SSL connection
- ADDED: Redis JSON format for String values #852
### 6.1.3
- FIXED: Fulltext search now shows correctly columns and SQL code lines
- ADDED: Configuration of SSH tunnel local host (IPv4 vs IPv6). Should fix majority of SSH tunnel problems
- FIXED: Handled SSH tunnel connection error, now it shows error instead of connecting forever
- ADDED: Support of triggers (SQLite)
- ADDED: Create, drop trigger
- ADDED: Support for MySQL scheduled events
- FIXED: Cannot connect to DB using askUser/askPassword mode #995
- FIXED: Filtering in Oracle #992
- ADDED: Open table in raw mode #991, #962
- ADDED: Introduced E2E Cypress tests, test refactor
### 6.1.1
- ADDED: Trigger support (SQL Server, PostgreSQL, MySQL, Oracle)
- FIXED: PostgreSQL and Oracle export #970
- FIXED: Cursor Becomes Stuck When Escaping "Case" #954
- CHANGED: Defualt search criteria for tables are names only
- FIXED: Search in packed list
### 6.1.0
- ADDED: Fulltext search in DB model and connections, highlight searched names
- ADDED: Tab preview mode configuration #963
- CHANGED: Single-click to open server connection/database + ability to configure this #959
- ADDED: Option to align numbers to right in data grid #957
- FIXED: Cursor Becomes Stuck When Escaping "Case" #954
- ADDED: Postgres GEOGRAPHY types are shown on map, event when executing query #948
- FIXED: Error displaying CLOB and NCLOB in Oracle
- FIXED: Analysing of foreign keys in Postgres and MS SQL, when the same FKS are used across different schemas
- ADDED: Support of views, procedures, functions to Oracle. Added integration tests for Oracle
- ADDED: Display "No rows" message, quick add new row
- ADDED: Choose default database from list
- ADDED: Default database is automatically selected on connect
- ADDED: Apple-Silicon-only build for Mac #949
- ADDED: Display comment into tables and column list #755
### 6.0.0
- ADDED: Order or filter the indexes for huge tables #922
- ADDED: Empty string filters
- CHANGED: (Premium) Workflow for new installation (used in Docker and AWS distribution)
- ADDED: Show stored procedure and function parameters (MySQL, PostgreSQL, SQL Server, MariaDB) #348
- FIXED: Selected database has changed when closing database grouped tab #983
- ADDED: Add line break option to editor #823
- ADDED: Order or filter the indexes for huge tables #922
- ADDED: Preview mode for the top bar tab like vscode #767
- ADDED: Keyboard navigatioon between connections, databases and tables
- FIXED: Fixed some issues in connection search
- FIXED: Schema selection in Export does not provide all schemas #924
- CHANGED: Standardized Window menu in MacOS app
- FIXED: Typecast ::date is treated as a parameter #925
- FIXED: App crashes when trying to 'Open Structure' in a readonly connection #926
- FIXED: Selected database has changed when closing database grouped tab #938
- CHANGED: (Premium) Query designer and Query perspective designer moved to Premium editioin
- CHANGED: (Premium) Compare database tool - many improvements, moved to Premium edition
- ADDED: (Premium) Export DB model - exporting model to YAML folder, JSON or SQL folder
- CHANGED: Model deployer - many improvements, support of rename missing objects
- ADDED: (Premium) Premium NPM distribution
- CHANGED: (Premium) Amazon Redshift driver moved to Premium edition
- ADDED: Generated API documentation https://dbgate.org/docs/apidoc.html
- ADDED: NPM distribution now supports all dbgate database connectors, many improvements NPM packages
- CHANGED: Optimalized size of NPM plugins (eg. dbgate-plugin-mssql from 1.34 MB to 71 kB)
- CHANGED: Unsaved connections are now shown in "Recent and unsaved" folder after disconnect
- FIXED: Correctly show focused control, as defined by UX standards
- ADDED: Data duplicator - weak references
- ADDED: View JSON detail of log messages from export/import jobs and query executions
- ADDED: Rename procedure/function context menu
- ADDED: Show SQL quick view
### 5.5.6
- FIXED: DbGate process consumes 100% after UI closed - Mac, Linux (#917, #915)

View File

@@ -17,7 +17,8 @@ DbGate is licensed under GPL-3.0 license and is free to use for any purpose.
* Try it online - [demo.dbgate.org](https://demo.dbgate.org) - online demo application
* **Download** application for Windows, Linux or Mac from [dbgate.org](https://dbgate.org/download/)
* Run web version as [NPM package](https://www.npmjs.com/package/dbgate-serve) or as [docker image](https://hub.docker.com/r/dbgate/dbgate)
* Use nodeJs [scripting interface](https://dbgate.org/docs/scripting.html) ([API documentation](https://dbgate.org/docs/apidoc.html))
* Use nodeJs [scripting interface](https://dbgate.org/docs/scripting) ([API documentation](https://dbgate.org/docs/apidoc))
* [Recommend DbGate](https://testimonial.to/dbgate) | [Rate on G2](https://www.g2.com/products/dbgate/reviews)
## Supported databases
* MySQL
@@ -52,13 +53,15 @@ DbGate is licensed under GPL-3.0 license and is free to use for any purpose.
<!-- ![Screenshot](https://raw.githubusercontent.com/dbgate/dbgate/master/screenshot.png) -->
## Features
* Browse table data with many filtering options, Excel-like filters, multi-value filters
* Table data editing, with SQL change script preview
* Edit table schema, indexes, primary and foreign keys
* Compare and synchronize database structure
* ER diagram
* Light and dark theme
* Master/detail views, foreign key lookups
* Query designer
* Light and dark theme, next themes available as plugins from github community
* Huge support for work with related data - master/detail views, foreign key lookups, expanding columns from related tables in flat data view
* Query designer - visual SQL query builder without writing SQL code. Complex conditions like WHERE NOT EXISTS.
* Query perspectives innovative nested table view over complex relational data, something like query designer on MongoDB databases
* Form view for comfortable work with tables with many columns
* JSON view on MongoDB collections
* Explore tables, views, procedures, functions, MongoDB collections
@@ -70,13 +73,13 @@ DbGate is licensed under GPL-3.0 license and is free to use for any purpose.
* Mongo JavaScript editor, execute Mongo script (with NodeJs syntax)
* Redis tree view, generate script from keys, run Redis script
* Runs as application for Windows, Linux and Mac. Or in Docker container on server and in web Browser on client.
* Import, export from/to CSV, Excel, JSON, NDJSON, XML
* Import, export from/to CSV, Excel, JSON, NDJSON, XML, DBF
* Archives - backup your data in NDJSON files on local filesystem (or on DbGate server, when using web application)
* NDJSON data viewer and editor - browse NDJSON data, edit data and structure directly on NDJSON files. Works also for big NDSON files
* Charts, export chart to HTML page
* Show GEO data on map, export map to HTML page
* For detailed info, how to run DbGate in docker container, visit [docker hub](https://hub.docker.com/r/dbgate/dbgate)
* Extensible plugin architecture
* Perspectives - nested table view over complex relational data, query designer on MongoDB databases
## How to contribute
Any contributions are welcome. If you want to contribute without coding, consider following:
@@ -86,7 +89,7 @@ Any contributions are welcome. If you want to contribute without coding, conside
* Create issue, if you find problem in app, or you have idea to new feature. If issue already exists, you could leave comment on it, to prioritise most wanted issues
* Create some tutorial video on [youtube](https://www.youtube.com/playlist?list=PLCo7KjCVXhr0RfUSjM9wJMsp_ShL1q61A)
* Become a backer on [GitHub sponsors](https://github.com/sponsors/dbgate) or [Open collective](https://opencollective.com/dbgate)
* Where a small coding is acceptable for you, you could [create plugin](https://dbgate.org/docs/plugin-development.html). Plugins for new themes can be created actually without JS coding
* Where a small coding is acceptable for you, you could [create plugin](https://dbgate.org/docs/plugin-development). Plugins for new themes can be created actually without JS coding
Thank you!

View File

@@ -41,6 +41,29 @@ function adjustFile(file, isApp = false) {
delete json.optionalDependencies.msnodesqlv8;
}
if (process.argv.includes('--community')) {
delete json.optionalDependencies['mongodb-client-encryption'];
}
if (isApp && process.argv.includes('--premium')) {
json.build.win.target = [
{
target: 'nsis',
arch: ['x64'],
},
];
json.build.linux.target = [
{
target: 'AppImage',
arch: ['x64'],
},
];
json.name = 'dbgate-premium';
json.build.artifactName = 'dbgate-premium-${version}-${os}_${arch}.${ext}';
json.build.appId = 'org.dbgate.premium';
json.build.productName = 'DbGate Premium';
}
fs.writeFileSync(file, JSON.stringify(json, null, 2), 'utf-8');
}

View File

@@ -1,6 +1,6 @@
{
"name": "dbgate",
"version": "5.0.0-alpha.1",
"version": "6.0.0-alpha.1",
"private": true,
"author": "Jan Prochazka <jenasoft.database@gmail.com>",
"description": "Opensource database administration tool",
@@ -19,7 +19,6 @@
"artifactName": "dbgate-${version}-${os}_${arch}.${ext}",
"appId": "org.dbgate",
"productName": "DbGate",
"afterSign": "electron-builder-notarize",
"asarUnpack": "**/*.node",
"mac": {
"category": "database",
@@ -38,9 +37,11 @@
"target": "default",
"arch": [
"universal",
"x64"
"x64",
"arm64"
]
}
},
"notarize": true
},
"linux": {
"target": [
@@ -109,7 +110,8 @@
"files": [
"packages",
"src",
"icon.png"
"icon.png",
"!node_modules/cpu-features/build/**"
]
},
"homepage": "./",
@@ -128,7 +130,6 @@
"copyfiles": "^2.2.0",
"cross-env": "^6.0.3",
"electron": "30.0.2",
"electron-builder": "23.1.0",
"electron-builder-notarize": "^1.5.2"
"electron-builder": "25.1.8"
}
}

View File

@@ -108,7 +108,7 @@ function commandItem(item) {
}
function buildMenu() {
let template = _cloneDeepWith(mainMenuDefinition({ editMenu: true }), item => {
let template = _cloneDeepWith(mainMenuDefinition({ editMenu: true, isMac: isMac() }), item => {
if (item.divider) {
return { type: 'separator' };
}

View File

@@ -1,4 +1,4 @@
module.exports = ({ editMenu }) => [
module.exports = ({ editMenu, isMac }) => [
{
label: 'File',
submenu: [
@@ -24,20 +24,6 @@ module.exports = ({ editMenu }) => [
{ command: 'app.disconnect', hideDisabled: true, skipInApp: true },
],
},
{
label: 'Window',
submenu: [
{ command: 'tabs.closeTab', hideDisabled: false },
{ command: 'tabs.closeAll', hideDisabled: false },
{ command: 'tabs.closeTabsWithCurrentDb', hideDisabled: false },
{ command: 'tabs.closeTabsButCurrentDb', hideDisabled: false },
{ divider: true },
{ command: 'app.zoomIn', hideDisabled: true },
{ command: 'app.zoomOut', hideDisabled: true },
{ command: 'app.zoomReset', hideDisabled: true },
],
},
editMenu
? {
label: 'Edit',
@@ -75,6 +61,15 @@ module.exports = ({ editMenu }) => [
{ divider: true },
{ command: 'theme.changeTheme', hideDisabled: true },
{ command: 'settings.show' },
{ divider: true },
{ command: 'tabs.closeTab', hideDisabled: false },
{ command: 'tabs.closeAll', hideDisabled: false },
{ command: 'tabs.closeTabsWithCurrentDb', hideDisabled: false },
{ command: 'tabs.closeTabsButCurrentDb', hideDisabled: false },
{ divider: true },
{ command: 'app.zoomIn', hideDisabled: true },
{ command: 'app.zoomOut', hideDisabled: true },
{ command: 'app.zoomReset', hideDisabled: true },
],
},
{
@@ -94,6 +89,14 @@ module.exports = ({ editMenu }) => [
{ command: 'app.resetSettings', hideDisabled: true },
],
},
...(isMac
? [
{
role: 'window',
submenu: [{ role: 'minimize' }, { role: 'zoom' }, { type: 'separator' }, { role: 'front' }],
},
]
: []),
{
label: 'Help',
submenu: [

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
const directory = process.argv[2];
const fs = require('fs');
const volatilePackages = require('./volatilePackages');
const apiPackageJson = JSON.parse(fs.readFileSync(`packages/api/package.json`, { encoding: 'utf-8' }));
const dependencies = {};
const optionalDependencies = {};
for (const pkg of volatilePackages) {
if (pkg == 'msnodesqlv8' && process.platform != 'win32') {
continue;
}
if (apiPackageJson.dependencies[pkg]) {
dependencies[pkg] = apiPackageJson.dependencies[pkg];
}
if (apiPackageJson.optionalDependencies?.[pkg]) {
optionalDependencies[pkg] = apiPackageJson.optionalDependencies[pkg];
}
}
fs.writeFileSync(
`${directory}/package.json`,
JSON.stringify(
{
dependencies,
optionalDependencies,
},
null,
2
),
'utf-8'
);

174
common/processWorkflows.js Normal file
View File

@@ -0,0 +1,174 @@
const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');
const _ = require('lodash');
const indir = path.resolve(path.join(__dirname, '..', 'workflow-templates'));
const outdir = path.resolve(path.join(__dirname, '..', '.github', 'workflows'));
const includes = {};
const HEADER = `# --------------------------------------------------------------------------------------------
# This file is generated. Do not edit manually
# --------------------------------------------------------------------------------------------
`;
function readIncludes() {
for (const file of fs.readdirSync(indir)) {
const text = fs.readFileSync(path.join(indir, file), { encoding: 'utf-8' });
const json = yaml.load(text);
if (json._module) {
for (const key in json) {
if (key === '_module') {
continue;
}
includes[key] = json[key];
}
}
}
}
let modified = false;
function conditionMatch(condition, args) {
if (_.isString(condition)) {
return args.defs.includes(condition);
}
return false;
}
function processJsonStep(json, args) {
return _.cloneDeepWith(json, value => {
if (_.isArray(value)) {
const res = [];
let arrayModified = false;
for (const item of value) {
if (item._if) {
modified = true;
arrayModified = true;
if (conditionMatch(item._if, args)) {
res.push(_.omit(item, ['_if']));
}
} else if (item._replace || item._include) {
const replaceWith = item._replace ? args.replace?.[item._replace] : includes[item._include];
if (replaceWith) {
modified = true;
arrayModified = true;
if (_.isArray(replaceWith)) {
res.push(...replaceWith);
} else {
res.push(replaceWith);
}
} else {
res.push(item);
}
} else {
res.push(item);
}
}
if (arrayModified) {
return res;
}
return undefined;
}
if (_.isPlainObject(value)) {
if (_.intersection(args.allDefs ?? [], Object.keys(value))?.length > 0) {
modified = true;
for (const key in value) {
if (args.defs.includes(key)) {
return value[key];
}
}
return undefined;
}
}
if (_.isString(value)) {
let stringModified = false;
for (const key of Object.keys(args.stringReplace ?? {})) {
if (value.includes(key)) {
modified = true;
stringModified = true;
value = value.replaceAll(key, args.stringReplace[key]);
}
}
if (stringModified) {
return value;
}
return undefined;
}
if (value?._include) {
modified = true;
return includes[value?._include];
}
if (value?._replace) {
modified = true;
return args?.replace[value?._replace];
}
});
}
function processJson(json, args = {}) {
const MAX_STEPS = 64;
for (let i = 0; i < MAX_STEPS; i++) {
modified = false;
json = processJsonStep(json, args);
if (!modified) {
break;
}
}
return json;
}
function processFiles() {
const dumpOptions = {
lineWidth: -1,
};
for (const file of fs.readdirSync(indir)) {
const text = fs.readFileSync(path.join(indir, file), { encoding: 'utf-8' });
const json = yaml.load(text);
if (json._module) {
continue;
}
if (json._templates) {
const allDefs = Object.keys(json._templates);
for (const key in json._templates) {
allDefs.push(...(json._templates[key].defs ?? []));
}
for (const key in json._templates) {
const args = {
defs: [key, ...(json._templates[key]?.defs ?? [])],
replace: json._templates[key]?.replace,
stringReplace: json._templates[key]?.['string-replace'],
allDefs,
};
const converted = processJson(_.omit(json, ['_templates']), args);
const out = path.join(outdir, json._templates[key].file);
fs.writeFileSync(out, HEADER + yaml.dump(converted, dumpOptions));
}
} else {
fs.writeFileSync(path.join(outdir, file), HEADER + yaml.dump(processJson(json), dumpOptions));
}
}
}
function deleteOldFiles() {
const files = fs.readdirSync(outdir);
for (const file of files) {
fs.unlinkSync(path.join(outdir, file));
}
}
function run() {
deleteOldFiles();
readIncludes();
processFiles();
}
run();

View File

@@ -19,6 +19,7 @@ const volatilePackages = [
'activedirectory2',
'axios',
'ssh2',
'wkx',
];
module.exports = volatilePackages;

View File

@@ -0,0 +1,7 @@
FROM dexidp/dex:v2.35.3
COPY dex-config.yaml /etc/dex/cfg/config.yaml
EXPOSE 5556
CMD ["dex", "serve", "/etc/dex/cfg/config.yaml"]

View File

@@ -0,0 +1,22 @@
issuer: http://localhost:16009/dex
storage:
type: memory
web:
http: 0.0.0.0:5556
oauth2:
skipApprovalScreen: true
staticClients:
- id: my-app
redirectURIs:
- 'http://localhost:3000/'
name: 'My Test App'
secret: my-secret
enablePasswordDB: true
staticPasswords:
- email: "test@example.com"
hash: "$2y$10$JcmlXnV1y7.egUdKwYNbseOnqYVIGc323gtvvHh4ZuSPZB30veYZy"
username: "test"
userID: "1234"

View File

@@ -0,0 +1,27 @@
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y openssh-server mysql-server && \
apt-get clean && rm -rf /var/lib/apt/lists/*
RUN mkdir /var/run/sshd
RUN sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config && \
sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin without-password/' /etc/ssh/sshd_config
RUN mkdir -p /root/.ssh && chmod 700 /root/.ssh
COPY mykey.pub /root/.ssh/authorized_keys
RUN chmod 600 /root/.ssh/authorized_keys
RUN service mysql start && \
mysql -uroot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root'; FLUSH PRIVILEGES;" && \
service mysql stop
EXPOSE 22
COPY start.sh /start.sh
RUN chmod +x /start.sh
CMD ["/start.sh"]

View File

@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQClN/tu+X7PVYpMBEQDwxtyG0oNuKqcJdBud/vBUalyYSpliXO30BsBusjCyAh8ENVllmGTRaTcqAUPg/vwekaAMFZu9EXmQsdhPEWSxrkPkXXKsWrZVPtRV8l3wuSy/VLxbXRLujTpIEE5Au88e2CFN3zzuhg9rvsXE0cGjyYe9Cw3Ub+Yo6rbnESI7F+Jun29/wD8RF+kRL5cr7BrDoOBQf4yGexrTbUPMZ4b8QlGfXUwZhn6LlWVoWq7BMRelnfIAkuC+LwavvnkMqXMITmGa7sG0zOXByW7iGdP6TWVq9Ks+yCZoAA9ncAkgkpwoNrOSXR6dM5UjrsfJ2Na332QfxK8MmC+nBiyXIKUaQY2G8Wfm93GQqDc+349JFwH4ZjgYWJlTd/UfRCn4j30jxe1RKnjt5xGqb3L+j8JfuSPcojWRekg/K8GxBmaMCcEdqjIFD4MxeIUW3bGHd30wnuZkTPWlSmAGrO0fZXj0s1fmOBME05TjE8jsyKPmb2Kd3JdtCuTrjOgrYiHaMfcv/VqVhIv2kCKjnvhAxCqfGfKxxgcerItbrsfFAvYak1kwZelBquHOK6SkMH5WhDyhvGY+ZF0Wbg3CpynlpJVu4E3LSglYNbkIWqS3pAf+hqJtXl9SHCLgKFUcCIz0ZNQkT+PtUlR3klp6qoPXUWrcL3pdQ== test

View File

@@ -0,0 +1,7 @@
#!/bin/bash
service ssh start
service mysql start
tail -f /dev/null

View File

@@ -0,0 +1,23 @@
FROM ubuntu:22.04
RUN apt-get update && \
apt-get install -y openssh-server mysql-server && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN mkdir /var/run/sshd
RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
RUN echo 'root:root' | chpasswd
RUN service mysql start && \
mysql -uroot -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root'; FLUSH PRIVILEGES;" && \
service mysql stop
EXPOSE 22
COPY start.sh /start.sh
RUN chmod +x /start.sh
CMD ["/start.sh"]

View File

@@ -0,0 +1,7 @@
#!/bin/bash
service ssh start
service mysql start
tail -f /dev/null

View File

@@ -0,0 +1,44 @@
const { defineConfig } = require('cypress');
const killPort = require('kill-port');
const { clearTestingData } = require('./e2eTestTools');
const waitOn = require('wait-on');
const { exec } = require('child_process');
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
on('before:spec', async details => {
await clearTestingData();
// console.log('********************* DETAILS *********************', JSON.stringify(details));
if (config.isInteractive) {
await killPort(3000);
switch (details.fileName) {
case 'add-connection':
serverProcess = exec('yarn start:add-connection');
break;
case 'portal':
serverProcess = exec('yarn start:portal');
break;
case 'oauth':
serverProcess = exec('yarn start:oauth');
break;
case 'browse-data':
serverProcess = exec('yarn start:browse-data');
break;
}
await waitOn({ resources: ['http://localhost:3000'] });
serverProcess.stdout.on('data', data => {
console.log(data.toString());
});
serverProcess.stderr.on('data', data => {
console.error(data.toString());
});
}
});
},
},
});

View File

@@ -0,0 +1,109 @@
const path = require('path');
describe('Add connection', () => {
it('successfully loads', () => {
cy.visit('http://localhost:3000');
cy.contains('Database not selected');
});
it('adds connection', () => {
cy.visit('http://localhost:3000');
// cy.get('[data-testid=ConnectionList_buttonNewConnection]').click();
cy.get('[data-testid=ConnectionDriverFields_connectionType]').select('MySQL');
cy.get('[data-testid=ConnectionDriverFields_user]').clear().type('root');
cy.get('[data-testid=ConnectionDriverFields_password]').clear().type('Pwd2020Db');
cy.get('[data-testid=ConnectionDriverFields_port]').clear().type('16004');
cy.get('[data-testid=ConnectionDriverFields_displayName]').clear().type('test-mysql-1');
// test connection
cy.get('[data-testid=ConnectionTab_buttonTest]').click();
cy.contains('Connected:');
// save and connect
cy.get('[data-testid=ConnectionTab_buttonSave]').click();
cy.get('[data-testid=ConnectionTab_buttonConnect]').click();
cy.contains('performance_schema');
});
it('SSH connection - user + password', () => {
cy.visit('http://localhost:3000');
cy.contains('Connections');
// cy.realPress('F1');
// cy.realType('Close all');
// cy.realPress('Enter');
cy.get('[data-testid=ConnectionList_buttonNewConnection]').click();
cy.get('[data-testid=ConnectionDriverFields_connectionType]').select('MySQL');
cy.get('[data-testid=ConnectionDriverFields_user]').clear().type('root');
cy.get('[data-testid=ConnectionDriverFields_password]').clear().type('root');
cy.get('[data-testid=ConnectionDriverFields_displayName]').clear().type('test-mysql-ssh-1');
cy.get('[data-testid=ConnectionTab_tabSshTunnel]').click();
cy.get('[data-testid=ConnectionSshTunnelFields_useSshTunnel]').check();
cy.get('[data-testid=ConnectionSshTunnelFields_sshLogin]').clear().type('root');
cy.get('[data-testid=ConnectionSshTunnelFields_sshPassword]').clear().type('root');
cy.get('[data-testid=ConnectionSshTunnelFields_sshPort]').clear().type('16006');
cy.get('[data-testid=ConnectionTab_buttonSave]').click();
cy.get('[data-testid=ConnectionTab_buttonConnect]').click();
cy.contains('performance_schema');
});
it('SSH connection - keyfile', () => {
cy.visit('http://localhost:3000');
cy.contains('Connections');
// cy.realPress('F1');
// cy.realType('Close all');
// cy.realPress('Enter');
cy.get('[data-testid=ConnectionList_buttonNewConnection]').click();
cy.get('[data-testid=ConnectionDriverFields_connectionType]').select('MySQL');
cy.get('[data-testid=ConnectionDriverFields_user]').clear().type('root');
cy.get('[data-testid=ConnectionDriverFields_password]').clear().type('root');
cy.get('[data-testid=ConnectionDriverFields_displayName]').clear().type('test-mysql-ssh-2');
cy.get('[data-testid=ConnectionTab_tabSshTunnel]').click();
cy.get('[data-testid=ConnectionSshTunnelFields_useSshTunnel]').check();
cy.get('[data-testid=ConnectionSshTunnelFields_sshMode]').select('Key file');
cy.get('[data-testid=ConnectionSshTunnelFields_sshLogin]').clear();
cy.get('[data-testid=ConnectionSshTunnelFields_sshLogin]').type('root');
cy.get('[data-testid=ConnectionSshTunnelFields_sshKeyfile]')
.clear()
.type(path.join(Cypress.config('fileServerFolder'), 'cypress', 'e2e', 'mykey'));
cy.get('[data-testid=ConnectionSshTunnelFields_sshPort]').clear().type('16008');
cy.get('[data-testid=ConnectionTab_buttonSave]').click();
cy.get('[data-testid=ConnectionTab_buttonConnect]').click();
cy.contains('performance_schema');
});
it('ask password - mysql', () => {
cy.visit('http://localhost:3000');
cy.get('[data-testid=ConnectionList_buttonNewConnection]').click();
cy.get('[data-testid=ConnectionDriverFields_connectionType]').select('MySQL');
cy.get('[data-testid=ConnectionDriverFields_user]').clear().type('root');
cy.get('[data-testid=ConnectionDriverFields_password]').clear().type('Pwd2020Db');
cy.get('[data-testid=ConnectionDriverFields_port]').clear().type('16004');
cy.get('[data-testid=ConnectionDriverFields_displayName]').clear().type('test-mysql-2');
cy.testid('ConnectionDriverFields_passwordMode').select('askPassword');
// test connection
cy.get('[data-testid=ConnectionTab_buttonTest]').click();
cy.testid('DatabaseLoginModal_password').clear().type('Pwd2020Db');
cy.testid('DatabaseLoginModal_connect').click();
cy.contains('Connected:');
cy.get('[data-testid=ConnectionTab_buttonSave]').click();
cy.get('[data-testid=ConnectionTab_buttonConnect]').click();
// again type DB password - not saved
cy.testid('DatabaseLoginModal_password').clear().type('Pwd2020Db');
cy.testid('DatabaseLoginModal_connect').click();
cy.contains('performance_schema');
});
});

View File

@@ -0,0 +1,43 @@
describe('Data browser data', () => {
it('Load table data', () => {
cy.visit('http://localhost:3000');
cy.contains('MySql-connection').click();
cy.contains('Chinook').click();
cy.contains('Album').click();
cy.contains('Let There Be Rock').click();
cy.contains('Rows: 347');
cy.realPress(['Control', 'ArrowRight']);
cy.contains('Aerosmith');
});
it.only('Filter model', () => {
cy.visit('http://localhost:3000');
cy.contains('MySql-connection').click();
cy.contains('Chinook').click();
cy.testid('SqlObjectList_search').clear().type('album');
cy.contains('Tables (1/11)');
cy.contains('347 rows, InnoDB');
cy.testid('SqlObjectList_searchMenuDropDown').click();
cy.contains('Column name').click();
cy.contains('Tables (2/11)');
cy.contains('AlbumId');
cy.contains('Column name').click();
cy.contains('AlbumId').should('not.exist');
cy.contains('Tables (1/11)');
});
it('Show raw data', () => {
cy.visit('http://localhost:3000');
cy.contains('MySql-connection').click();
cy.contains('Chinook').click();
cy.contains('Album').rightclick();
cy.contains('Open raw data').click();
cy.contains('Let There Be Rock').click();
cy.contains('Rows: 347').should('not.exist');
cy.realPress(['Control', 'ArrowRight']);
cy.contains('Aerosmith').should('not.exist');
});
});

View File

@@ -0,0 +1,49 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAgEApTf7bvl+z1WKTAREA8MbchtKDbiqnCXQbnf7wVGpcmEqZYlzt9Ab
AbrIwsgIfBDVZZZhk0Wk3KgFD4P78HpGgDBWbvRF5kLHYTxFksa5D5F1yrFq2VT7UVfJd8
Lksv1S8W10S7o06SBBOQLvPHtghTd887oYPa77FxNHBo8mHvQsN1G/mKOq25xEiOxfibp9
vf8A/ERfpES+XK+waw6DgUH+Mhnsa021DzGeG/EJRn11MGYZ+i5VlaFquwTEXpZ3yAJLgv
i8Gr755DKlzCE5hmu7BtMzlwclu4hnT+k1lavSrPsgmaAAPZ3AJIJKcKDazkl0enTOVI67
HydjWt99kH8SvDJgvpwYslyClGkGNhvFn5vdxkKg3Pt+PSRcB+GY4GFiZU3f1H0Qp+I99I
8XtUSp47ecRqm9y/o/CX7kj3KI1kXpIPyvBsQZmjAnBHaoyBQ+DMXiFFt2xh3d9MJ7mZEz
1pUpgBqztH2V49LNX5jgTBNOU4xPI7Mij5m9indyXbQrk64zoK2Ih2jH3L/1alYSL9pAio
574QMQqnxnyscYHHqyLW67HxQL2GpNZMGXpQarhziukpDB+VoQ8obxmPmRdFm4Nwqcp5aS
VbuBNy0oJWDW5CFqkt6QH/oaibV5fUhwi4ChVHAiM9GTUJE/j7VJUd5JaeqqD11Fq3C96X
UAAAdAKwO+PisDvj4AAAAHc3NoLXJzYQAAAgEApTf7bvl+z1WKTAREA8MbchtKDbiqnCXQ
bnf7wVGpcmEqZYlzt9AbAbrIwsgIfBDVZZZhk0Wk3KgFD4P78HpGgDBWbvRF5kLHYTxFks
a5D5F1yrFq2VT7UVfJd8Lksv1S8W10S7o06SBBOQLvPHtghTd887oYPa77FxNHBo8mHvQs
N1G/mKOq25xEiOxfibp9vf8A/ERfpES+XK+waw6DgUH+Mhnsa021DzGeG/EJRn11MGYZ+i
5VlaFquwTEXpZ3yAJLgvi8Gr755DKlzCE5hmu7BtMzlwclu4hnT+k1lavSrPsgmaAAPZ3A
JIJKcKDazkl0enTOVI67HydjWt99kH8SvDJgvpwYslyClGkGNhvFn5vdxkKg3Pt+PSRcB+
GY4GFiZU3f1H0Qp+I99I8XtUSp47ecRqm9y/o/CX7kj3KI1kXpIPyvBsQZmjAnBHaoyBQ+
DMXiFFt2xh3d9MJ7mZEz1pUpgBqztH2V49LNX5jgTBNOU4xPI7Mij5m9indyXbQrk64zoK
2Ih2jH3L/1alYSL9pAio574QMQqnxnyscYHHqyLW67HxQL2GpNZMGXpQarhziukpDB+VoQ
8obxmPmRdFm4Nwqcp5aSVbuBNy0oJWDW5CFqkt6QH/oaibV5fUhwi4ChVHAiM9GTUJE/j7
VJUd5JaeqqD11Fq3C96XUAAAADAQABAAACAAOZKogKNbF8+BwbuQIpTP8Oim2uE0PUrFYb
lYdqUznDKqc3d9ENs+jfu+DyIQKCuK2+ZAr5vf4dnVlEffIzgjbnK/ASsIsJR/UILlkPVu
x4izY06FIqFackivtpao2zaAu2CeMJqn6r+H+uCVkp3rpIBm1QekKtqEOiZIOcuS8nZjx2
MqliYdA9S7N9DRT0037rKjGpqOOXqQW1FdnfC7d+9nL6OY9EtqgeuTDRQ8BzRGAfeSVdE6
QZ9eHI2CCvP5XtkYjICLYUaWDc8YYhRcggWdxrhnjIQRF1MRApJhpHubjmvJkGm7q70CQm
FPT1q+OeRJko022SsOScI6p7qkJjEsHS4RLbSGkDAn84U9l1MnHbzOqOQbI/Mnn7vNyZt4
e7n/ExUg9HglpdLgETl0oLIaiVgYGrJSLflfYtrgfEISGtoroQDj/X96HZsF+Aku+I3U4z
OD7UasFDl3LsTO3bWz8/vqkCfi/ncejZ4keWUA6VahbtJUg8E/eEIWMz8gFoO/vWf1l0H0
V51ISzInt1yVnqhdbRPH+Ce4NlNjq9JlhiZVJSsc6ke2580Okttc3JETzdHWNac7k+/0u4
lPZK2sII1cq/d+9YAe3JVpUuiQyX6R4Crga2GIyevoqm3EyXUNN/vjDCx4qyToOtJUzHao
tXI4tZZkBmtVrhqf1pAAABAQC3lG50iMbJXL8vVsB7P8UWLgmI13PqwHB8ldzsLrNtkU7q
N3KYdz/ycGGPAKxfMJiGs00qT8/d107MZYmj7hHE84VuBiHVGSXbzmL5zeth0aN4oINee0
jlvCPKjqhoImPtrU1fLglqOeTNJcZK7XzwiZry1ZHp0hXd4XPrWHZBZo37SYv9/t652zR4
qmXlxwwwdtzuNFiAexTu0K4zY12hjmoGlvlCS2YJ+B2wJNd3E1RnL505m7dIA/dLnCLeEj
zf8j1XiZ9i/m7mrU/g/e9SFP+HVwi5AV5eyHbNSPD6GZ7quWL4SlP+GGkNtKden+LIaB+G
iRwCLTgCVThdIC6oAAABAQDA6Gm7luZuzOoWBQzVKc74AOf64Op+eZwQBCC3V+eHjmyIQW
oBozvlvaNxapNxJZQjtnlckCkW59RheQxm155j/MV6aVvaD9WWNFB9k+0fujmPd4fPoZF1
9y5J3L3l9hmv+51vZvKvky5mXxOGdONTQZkpGqGvmlZpVO9jWe4WWACokqRIrS9zwtfLgf
hH+hUMh+9R1iIKACleNdfHbiqia+XIXxivbVdCtTgdPM6mW8i3gP1/oSTpYZI5KIRH4PTO
6OgG8EvRCIPc/0mddXZqiabhpPM/r5qe0jKxcQHFf1siwq7EyZ/C8ctBxpEK4dVCNnCTX4
k7+/JizOJzhzljAAABAQDbQT0BsBCM2Dl+LbwpAy6iaS0fWqhCnQ9B6ojWcfNouXuIW4tF
6fwmoqyFU2SoORmj0G6ww1NiBr+gwSDo5wSEpCI78S1CnFcp7J1HhONGthmdYDclpDlci5
t5AOIC7hhmdkqL46happxG9MH8oOua7/cqK7300nJo+ZS3XOo4O3siTjDVtVKXRAY5jWuG
mLNXQ8JKCzqmFfLlAAgGWaY7rMaGu+9Rom+F4FEZ4IUitcsN77jFNBXMXqnWy/ayr8CJpe
CxgwBm5JWQ7m+cmskMl3nmjkNr8nCiZoMcz4sIrVkZWS4PHoVFtN3jKYmo3c02kq8/378I
jIy5WYf/zrVHAAAABHRlc3QBAgMEBQY=
-----END OPENSSH PRIVATE KEY-----

View File

@@ -0,0 +1,14 @@
describe('OAuth', () => {
it('OAuth login', () => {
cy.visit('http://localhost:3000');
// login on DEX
cy.get('#login').clear().type('test@example.com');
cy.get('#password').clear().type('test');
cy.get('#submit-login').click();
// check DbGate connection
cy.contains('MySql-connection').click();
cy.contains('performance_schema');
});
});

View File

@@ -0,0 +1,93 @@
describe('Run as portal', () => {
it('successfully loads', () => {
cy.visit('http://localhost:3000');
cy.contains('MySql-connection');
cy.contains('Postgres-connection');
});
// it('Delete chinook', () => {
// cy.visit('http://localhost:3000');
// cy.contains('MySql-connection').rightclick();
// cy.contains('New Query (server)').click();
// cy.realType('drop database if exists Chinook');
// cy.realPress('F5');
// cy.contains('Query execution finished');
// cy.contains('Postgres-connection').rightclick();
// cy.contains('New Query (server)').click();
// cy.realType('drop database if exists "Chinook"');
// cy.realPress('F5');
// cy.contains('Query execution finished');
// // cy.realPress('F1');
// // cy.realType('Close all');
// // cy.realPress('Enter');
// });
it('Create Chinook MySQL', () => {
cy.visit('http://localhost:3000');
cy.contains('MySql-connection').click();
cy.contains('MySql-connection').rightclick();
cy.contains('Create database').click();
cy.get('[data-testid=InputTextModal_value]').clear().type('Chinook');
cy.get('[data-testid=InputTextModal_ok]').click();
});
it('Create Chinook Postgres', () => {
cy.visit('http://localhost:3000');
cy.contains('Postgres-connection').click();
cy.contains('Postgres-connection').rightclick();
cy.contains('Create database').click();
cy.get('[data-testid=InputTextModal_value]').clear().type('Chinook');
cy.get('[data-testid=InputTextModal_ok]').click();
});
it('Import Chinook MySQL', () => {
cy.visit('http://localhost:3000');
cy.contains('MySql-connection').click();
cy.get('[data-testid=DatabaseAppObject_Chinook]').rightclick();
cy.contains('Chinook').rightclick();
cy.contains('Restore/import SQL dump').click();
cy.get('#uploadFileButton').selectFile('data/chinook-mysql.sql', { force: true });
cy.wait(500);
cy.get('[data-testid=ImportDatabaseDumpModal_runImport]').click();
cy.contains('Importing database');
cy.contains('Finished job script');
cy.get('[data-testid=RunScriptModal_close]').click();
cy.contains('Chinook').click();
cy.contains('Album');
});
it('Import Chinook Postgres', () => {
cy.visit('http://localhost:3000');
cy.contains('Postgres-connection').click();
cy.get('[data-testid=DatabaseAppObject_Chinook]').rightclick();
cy.contains('Restore/import SQL dump').click();
cy.get('#uploadFileButton').selectFile('data/chinook-postgres.sql', { force: true });
cy.wait(500);
cy.get('[data-testid=ImportDatabaseDumpModal_runImport]').click();
cy.contains('Importing database');
cy.contains('Finished job script');
cy.get('[data-testid=RunScriptModal_close]').click();
cy.contains('Chinook').click();
cy.contains('album');
});
it('Open ask pwd connection', () => {
cy.visit('http://localhost:3000');
cy.contains('Postgres-ask-connection').click();
cy.testid('DatabaseLoginModal_username').clear().type('postgres');
cy.testid('DatabaseLoginModal_password').clear().type('Pwd2020Db');
cy.testid('DatabaseLoginModal_connect').click();
cy.contains('Chinook').click();
cy.contains('album');
});
// it('import chinook DB', () => {
// cy.visit('http://localhost:3000');
// cy.get('[data-testid=ConnectionTab_buttonConnect]').click();
// });
});

View File

@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "hello@cypress.io",
"body": "Fixtures are a great way to mock data for responses to routes"
}

View File

@@ -0,0 +1,29 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add('login', (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This will overwrite an existing command --
// Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... })
Cypress.Commands.add('testid', (testId, options = {}) => {
return cy.get(`[data-testid="${testId}"]`, options);
});

View File

@@ -0,0 +1,44 @@
// ***********************************************************
// This example support/e2e.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')
import 'cypress-real-events';
beforeEach(() => {
// Replace 'my-database-name' with the actual IndexedDB name
cy.window().then(win => {
return new Promise((resolve, reject) => {
const request = win.indexedDB.deleteDatabase('localforage');
request.onsuccess = () => {
// Database successfully deleted
resolve();
};
request.onerror = () => {
// Some error occurred
reject(request.error);
};
request.onblocked = () => {
// Might happen if there are open connections
console.warn('IndexedDB deletion blocked');
resolve();
};
});
});
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,37 @@
version: '3'
services:
postgres:
image: postgres
restart: always
environment:
POSTGRES_PASSWORD: Pwd2020Db
ports:
- 16000:5432
mariadb:
image: mariadb
command: --default-authentication-plugin=mysql_native_password
restart: always
ports:
- 16004:3306
environment:
- MYSQL_ROOT_PASSWORD=Pwd2020Db
mysql-ssh-login:
build: containers/mysql-ssh-login
restart: always
ports:
- 16005:3306
- "16006:22"
mysql-ssh-keyfile:
build: containers/mysql-ssh-keyfile
restart: always
ports:
- 16007:3306
- "16008:22"
dex:
build: containers/dex
ports:
- "16009:5556"

29
e2e-tests/e2eTestTools.js Normal file
View File

@@ -0,0 +1,29 @@
const path = require('path');
const os = require('os');
const fs = require('fs');
const baseDir = path.join(os.homedir(), '.dbgate');
// function createTimeStamp() {
// const now = new Date();
// const year = now.getFullYear();
// const month = String(now.getMonth() + 1).padStart(2, '0'); // měsíc je 0-indexovaný
// const day = String(now.getDate()).padStart(2, '0');
// const hours = String(now.getHours()).padStart(2, '0');
// const minutes = String(now.getMinutes()).padStart(2, '0');
// const seconds = String(now.getSeconds()).padStart(2, '0');
// // Poskládáme datum a čas do názvu souboru
// const ts = `${year}-${month}-${day}_${hours}-${minutes}-${seconds}`;
// return ts;
// }
function clearTestingData() {
if (fs.existsSync(path.join(baseDir, 'connections-e2etests.jsonl'))) {
fs.unlinkSync(path.join(baseDir, 'connections-e2etests.jsonl'));
}
}
module.exports = {
clearTestingData,
};

8
e2e-tests/env/browse-data/.env vendored Normal file
View File

@@ -0,0 +1,8 @@
CONNECTIONS=mysql
LABEL_mysql=MySql-connection
SERVER_mysql=localhost
USER_mysql=root
PASSWORD_mysql=Pwd2020Db
PORT_mysql=16004
ENGINE_mysql=mysql@dbgate-plugin-mysql

15
e2e-tests/env/oauth/.env vendored Normal file
View File

@@ -0,0 +1,15 @@
CONNECTIONS=mysql
LABEL_mysql=MySql-connection
SERVER_mysql=localhost
USER_mysql=root
PASSWORD_mysql=Pwd2020Db
PORT_mysql=16004
ENGINE_mysql=mysql@dbgate-plugin-mysql
OAUTH_AUTH=http://localhost:16009/dex/auth
OAUTH_TOKEN=http://localhost:16009/dex/token
OAUTH_CLIENT_ID=my-app
OAUTH_CLIENT_SECRET=my-secret
OAUTH_LOGIN_FIELD=username
OAUTH_SCOPE=openid

22
e2e-tests/env/portal/.env vendored Normal file
View File

@@ -0,0 +1,22 @@
CONNECTIONS=mysql,postgres,pgask
LABEL_mysql=MySql-connection
SERVER_mysql=localhost
USER_mysql=root
PASSWORD_mysql=Pwd2020Db
PORT_mysql=16004
ENGINE_mysql=mysql@dbgate-plugin-mysql
LABEL_postgres=Postgres-connection
SERVER_postgres=localhost
USER_postgres=postgres
PASSWORD_postgres=Pwd2020Db
PORT_postgres=16000
ENGINE_postgres=postgres@dbgate-plugin-postgres
LABEL_pgask=Postgres-ask-connection
SERVER_pgask=localhost
USER_pgask=postgres
PORT_pgask=16000
ENGINE_pgask=postgres@dbgate-plugin-postgres
PASSWORD_MODE_pgask=askUser

View File

@@ -0,0 +1,43 @@
const dbgateApi = require('dbgate-api');
dbgateApi.initializeApiEnvironment();
const dbgatePluginMysql = require('dbgate-plugin-mysql');
dbgateApi.registerPlugins(dbgatePluginMysql);
const dbgatePluginPostgres = require('dbgate-plugin-postgres');
dbgateApi.registerPlugins(dbgatePluginPostgres);
async function run() {
await dbgateApi.executeQuery({
connection: {
server: process.env.SERVER_mysql,
user: process.env.USER_mysql,
password: process.env.PASSWORD_mysql,
port: process.env.PORT_mysql,
engine: 'mysql@dbgate-plugin-mysql',
},
sql: 'drop database if exists Chinook',
});
await dbgateApi.executeQuery({
connection: {
server: process.env.SERVER_mysql,
user: process.env.USER_mysql,
password: process.env.PASSWORD_mysql,
port: process.env.PORT_mysql,
engine: 'mysql@dbgate-plugin-mysql',
},
sql: 'create database Chinook',
});
await dbgateApi.importDatabase({
connection: {
server: process.env.SERVER_mysql,
user: process.env.USER_mysql,
password: process.env.PASSWORD_mysql,
port: process.env.PORT_mysql,
engine: 'mysql@dbgate-plugin-mysql',
},
inputFile: '../data/Chinook-mysql.sql',
});
}
dbgateApi.runScript(run);

32
e2e-tests/init/portal.js Normal file
View File

@@ -0,0 +1,32 @@
const dbgateApi = require('dbgate-api');
dbgateApi.initializeApiEnvironment();
const dbgatePluginMysql = require('dbgate-plugin-mysql');
dbgateApi.registerPlugins(dbgatePluginMysql);
const dbgatePluginPostgres = require('dbgate-plugin-postgres');
dbgateApi.registerPlugins(dbgatePluginPostgres);
async function run() {
await dbgateApi.executeQuery({
connection: {
server: process.env.SERVER_mysql,
user: process.env.USER_mysql,
password: process.env.PASSWORD_mysql,
port: process.env.PORT_mysql,
engine: 'mysql@dbgate-plugin-mysql',
},
sql: 'drop database if exists Chinook',
});
await dbgateApi.executeQuery({
connection: {
server: process.env.SERVER_postgres,
user: process.env.USER_postgres,
password: process.env.PASSWORD_postgres,
port: process.env.PORT_postgres,
engine: 'postgres@dbgate-plugin-postgres',
},
sql: 'drop database if exists "Chinook"',
});
}
dbgateApi.runScript(run);

31
e2e-tests/package.json Normal file
View File

@@ -0,0 +1,31 @@
{
"name": "e2e-tests",
"version": "1.0.0",
"main": "index.js",
"license": "GPL",
"devDependencies": {
"axios": "^1.7.9",
"cross-env": "^7.0.3",
"cypress": "^13.16.1",
"cypress-real-events": "^1.13.0",
"env-cmd": "^10.1.0",
"kill-port": "^2.0.1",
"start-server-and-test": "^2.0.8"
},
"scripts": {
"cy:open": "cypress open --config experimentalInteractiveRunEvents=true",
"cy:run:add-connection": "cypress run --spec cypress/e2e/add-connection.cy.js",
"cy:run:portal": "cypress run --spec cypress/e2e/portal.cy.js",
"cy:run:oauth": "cypress run --spec cypress/e2e/oauth.cy.js",
"cy:run:browse-data": "cypress run --spec cypress/e2e/browse-data.cy.js",
"start:add-connection": "cd .. && node packer/build/bundle.js --listen-api --run-e2e-tests",
"start:portal": "cd .. && env-cmd -f e2e-tests/env/portal/.env node e2e-tests/init/portal.js && env-cmd -f e2e-tests/env/portal/.env node packer/build/bundle.js --listen-api --run-e2e-tests",
"start:oauth": "cd .. && env-cmd -f e2e-tests/env/oauth/.env node packer/build/bundle.js --listen-api --run-e2e-tests",
"start:browse-data": "cd .. && env-cmd -f e2e-tests/env/browse-data/.env node packer/build/bundle.js --listen-api --run-e2e-tests",
"test": "start-server-and-test start:add-connection http://localhost:3000 cy:run:add-connection && start-server-and-test start:portal http://localhost:3000 cy:run:portal && start-server-and-test start:oauth http://localhost:3000 cy:run:oauth && start-server-and-test start:browse-data http://localhost:3000 cy:run:browse-data",
"test:ci": "yarn test"
}
}

1381
e2e-tests/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -3,9 +3,15 @@ const _ = require('lodash');
const fp = require('lodash/fp');
const { testWrapper } = require('../tools');
const engines = require('../engines');
const { getAlterDatabaseScript, extendDatabaseInfo, generateDbPairingId } = require('dbgate-tools');
const {
getAlterDatabaseScript,
extendDatabaseInfo,
generateDbPairingId,
formatQueryWithoutParams,
runCommandOnDriver,
} = require('dbgate-tools');
const initSql = ['CREATE TABLE t1 (id int primary key)', 'CREATE TABLE t2 (id int primary key)'];
const initSql = ['CREATE TABLE ~t1 (~id int primary key)', 'CREATE TABLE ~t2 (~id int primary key)'];
function flatSource(engineCond = x => !x.skipReferences) {
return _.flatten(
@@ -16,13 +22,14 @@ function flatSource(engineCond = x => !x.skipReferences) {
}
async function testDatabaseDiff(conn, driver, mangle, createObject = null) {
await driver.query(conn, `create table t1 (id int not null primary key)`);
await runCommandOnDriver(conn, driver, `create table ~t1 (~id int not null primary key)`);
await driver.query(
await runCommandOnDriver(
conn,
`create table t2 (
id int not null primary key,
t1_id int null references t1(id)
driver,
`create table ~t2 (
~id int not null primary key,
~t1_id int null references ~t1(~id)
)`
);
@@ -63,29 +70,32 @@ describe('Alter database', () => {
db => {
_.remove(db[type], x => x.pureName == 'obj1');
},
object.create1
formatQueryWithoutParams(driver, object.create1)
);
expect(db[type].length).toEqual(0);
})
);
test.each(flatSource(x => x.supportRenameSqlObject))(
'Rename object - %s - %s',
testWrapper(async (conn, driver, type, object, engine) => {
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
const objectsSupportingRename = flatSource(x => x.supportRenameSqlObject);
if (objectsSupportingRename.length > 0) {
test.each(objectsSupportingRename)(
'Rename object - %s - %s',
testWrapper(async (conn, driver, type, object, engine) => {
for (const sql of initSql) await runCommandOnDriver(conn, driver, sql);
await driver.query(conn, object.create1, { discardResult: true });
await runCommandOnDriver(conn, driver, object.create1);
const structure = extendDatabaseInfo(await driver.analyseFull(conn));
const structure = extendDatabaseInfo(await driver.analyseFull(conn));
const dmp = driver.createDumper();
dmp.renameSqlObject(structure[type][0], 'renamed1');
const dmp = driver.createDumper();
dmp.renameSqlObject(structure[type][0], 'renamed1');
await driver.query(conn, dmp.s);
await driver.query(conn, dmp.s);
const structure2 = await driver.analyseFull(conn);
expect(structure2[type].length).toEqual(1);
expect(structure2[type][0].pureName).toEqual('renamed1');
})
);
const structure2 = await driver.analyseFull(conn);
expect(structure2[type].length).toEqual(1);
expect(structure2[type][0].pureName).toEqual('renamed1');
})
);
}
});

View File

@@ -4,7 +4,12 @@ const fp = require('lodash/fp');
const { testWrapper } = require('../tools');
const engines = require('../engines');
const crypto = require('crypto');
const { getAlterTableScript, extendDatabaseInfo, generateDbPairingId } = require('dbgate-tools');
const {
getAlterTableScript,
extendDatabaseInfo,
generateDbPairingId,
formatQueryWithoutParams,
} = require('dbgate-tools');
function pickImportantTableInfo(engine, table) {
const props = ['columnName', 'defaultValue'];
@@ -15,7 +20,10 @@ function pickImportantTableInfo(engine, table) {
columns: table.columns
.filter(x => x.columnName != 'rowid')
.map(fp.pick(props))
.map(props => _.omitBy(props, x => x == null)),
.map(props => _.omitBy(props, x => x == null))
.map(props =>
_.omitBy(props, (v, k) => k == 'defaultValue' && v == 'NULL' && engine.setNullDefaultInsteadOfDrop)
),
};
}
@@ -25,27 +33,36 @@ function checkTableStructure(engine, t1, t2) {
}
async function testTableDiff(engine, conn, driver, mangle) {
await driver.query(conn, `create table t0 (id int not null primary key)`);
await driver.query(conn, formatQueryWithoutParams(driver, `create table ~t0 (~id int not null primary key)`));
await driver.query(
conn,
`create table t1 (
col_pk int not null primary key,
col_std int,
col_def int default 12,
${engine.skipReferences ? '' : 'col_fk int references t0(id),'}
col_idx int,
col_uq int ${engine.skipUnique ? '' : 'unique'} ,
col_ref int ${engine.skipUnique ? '' : 'unique'}
formatQueryWithoutParams(
driver,
`create table ~t1 (
~col_pk int not null primary key,
~col_std int,
~col_def int default 12,
${engine.skipReferences ? '' : '~col_fk int references ~t0(~id),'}
~col_idx int,
~col_uq int ${engine.skipUnique ? '' : 'unique'} ,
~col_ref int ${engine.skipUnique ? '' : 'unique'}
)`
)
);
if (!engine.skipIndexes) {
await driver.query(conn, `create index idx1 on t1(col_idx)`);
await driver.query(conn, formatQueryWithoutParams(driver, `create index ~idx1 on ~t1(~col_idx)`));
}
if (!engine.skipReferences) {
await driver.query(conn, `create table t2 (id int not null primary key, fkval int null references t1(col_ref))`);
await driver.query(
conn,
formatQueryWithoutParams(
driver,
`create table ~t2 (~id int not null primary key, ~fkval int null references ~t1(~col_ref))`
)
);
}
const tget = x => x.tables.find(y => y.pureName == 't1');
@@ -166,4 +183,13 @@ describe('Alter table', () => {
});
})
);
// test.each(engines.map(engine => [engine.label, engine]))(
// 'Change autoincrement - %s',
// testWrapper(async (conn, driver, engine) => {
// await testTableDiff(engine, conn, driver, tbl => {
// tbl.columns.find(x => x.columnName == 'col_pk').autoIncrement = true;
// });
// })
// );
});

View File

@@ -2,7 +2,7 @@ const engines = require('../engines');
const stream = require('stream');
const { testWrapper } = require('../tools');
const dataDuplicator = require('dbgate-api/src/shell/dataDuplicator');
const { runCommandOnDriver } = require('dbgate-tools');
const { runCommandOnDriver, runQueryOnDriver } = require('dbgate-tools');
describe('Data duplicator', () => {
test.each(engines.filter(x => !x.skipDataDuplicator).map(engine => [engine.label, engine]))(
@@ -84,10 +84,10 @@ describe('Data duplicator', () => {
],
});
const res1 = await driver.query(conn, `select count(*) as cnt from t1`);
const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t1`));
expect(res1.rows[0].cnt.toString()).toEqual('6');
const res2 = await driver.query(conn, `select count(*) as cnt from t2`);
const res2 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t2`));
expect(res2.rows[0].cnt.toString()).toEqual('6');
})
);
@@ -145,13 +145,15 @@ describe('Data duplicator', () => {
},
});
const res1 = await driver.query(conn, `select count(*) as cnt from t1`);
const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t1`));
expect(res1.rows[0].cnt.toString()).toEqual('1');
const res2 = await driver.query(conn, `select count(*) as cnt from t2`);
const res2 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t2`));
expect(res2.rows[0].cnt.toString()).toEqual('2');
const res3 = await driver.query(conn, `select count(*) as cnt from t2 where valfk is not null`);
const res3 = await runQueryOnDriver(conn, driver, dmp =>
dmp.put(`select count(*) as ~cnt from ~t2 where ~valfk is not null`)
);
expect(res3.rows[0].cnt.toString()).toEqual('1');
})
);

View File

@@ -2,9 +2,11 @@ const engines = require('../engines');
const stream = require('stream');
const { testWrapper } = require('../tools');
const tableWriter = require('dbgate-api/src/shell/tableWriter');
const tableReader = require('dbgate-api/src/shell/tableReader');
const copyStream = require('dbgate-api/src/shell/copyStream');
const importDatabase = require('dbgate-api/src/shell/importDatabase');
const fakeObjectReader = require('dbgate-api/src/shell/fakeObjectReader');
const { runQueryOnDriver, runCommandOnDriver } = require('dbgate-tools');
function createImportStream() {
const pass = new stream.PassThrough({
@@ -22,7 +24,17 @@ function createImportStream() {
return pass;
}
describe('DB Import', () => {
function createExportStream() {
const writable = new stream.Writable({ objectMode: true });
writable.resultArray = [];
writable._write = (chunk, encoding, callback) => {
writable.resultArray.push(chunk);
callback();
};
return writable;
}
describe('DB Import/export', () => {
test.each(engines.map(engine => [engine.label, engine]))(
'Import one table - %s',
testWrapper(async (conn, driver, engine) => {
@@ -37,7 +49,7 @@ describe('DB Import', () => {
});
await copyStream(reader, writer);
const res = await driver.query(conn, `select count(*) as cnt from t1`);
const res = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t1`));
expect(res.rows[0].cnt.toString()).toEqual('6');
})
);
@@ -65,10 +77,10 @@ describe('DB Import', () => {
});
await copyStream(reader2, writer2);
const res1 = await driver.query(conn, `select count(*) as cnt from t1`);
const res1 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t1`));
expect(res1.rows[0].cnt.toString()).toEqual('6');
const res2 = await driver.query(conn, `select count(*) as cnt from t2`);
const res2 = await runQueryOnDriver(conn, driver, dmp => dmp.put(`select count(*) as ~cnt from ~t2`));
expect(res2.rows[0].cnt.toString()).toEqual('6');
})
);
@@ -98,4 +110,35 @@ describe('DB Import', () => {
// expect(res2.rows[0].cnt.toString()).toEqual('6');
})
);
test.each(engines.map(engine => [engine.label, engine]))(
'Export one table - %s',
testWrapper(async (conn, driver, engine) => {
// const reader = await fakeObjectReader({ delay: 10 });
// const reader = await fakeObjectReader();
await runCommandOnDriver(conn, driver, 'create table ~t1 (~id int primary key, ~country varchar(100))');
const data = [
[1, 'Czechia'],
[2, 'Austria'],
[3, 'Germany'],
[4, 'Romania'],
[5, 'Great Britain'],
[6, 'Bosna, Hecegovina'],
];
for (const row of data) {
await runCommandOnDriver(conn, driver, dmp =>
dmp.put('insert into ~t1(~id, ~country) values (%v, %v)', ...row)
);
}
const reader = await tableReader({
systemConnection: conn,
driver,
pureName: 't1',
});
const writer = createExportStream();
await copyStream(reader, writer);
expect(writer.resultArray.filter(x => !x.__isStreamHeader).map(row => [row.id, row.country])).toEqual(data);
})
);
});

View File

@@ -4,7 +4,7 @@ const { testWrapper, testWrapperPrepareOnly } = require('../tools');
const _ = require('lodash');
const engines = require('../engines');
const deployDb = require('dbgate-api/src/shell/deployDb');
const { databaseInfoFromYamlModel } = require('dbgate-tools');
const { databaseInfoFromYamlModel, runQueryOnDriver, formatQueryWithoutParams } = require('dbgate-tools');
const generateDeploySql = require('dbgate-api/src/shell/generateDeploySql');
const connectUtility = require('dbgate-api/src/utility/connectUtility');
@@ -69,6 +69,29 @@ function checkStructure(
}
}
// function convertObjectText(text, driver) {
// if (!text) return undefined;
// text = formatQueryWithoutParams(driver, text);
// if (driver.dialect.requireFromDual && text.startsWith('create view ') && !text.includes('from')) {
// text = text + ' from dual';
// }
// return text;
// }
// function convertModelToEngine(model, driver) {
// return model.map(x => ({
// ...x,
// text: convertObjectText(x.text, driver),
// }));
// }
function convertModelToEngine(model, driver) {
return model.map(x => ({
...x,
text: x.text ? formatQueryWithoutParams(driver, x.text) : undefined,
}));
}
async function testDatabaseDeploy(engine, conn, driver, dbModelsYaml, options) {
const { testEmptyLastScript, finalCheckAgainstModel, markDeleted, allowDropStatements } = options || {};
let index = 0;
@@ -82,30 +105,34 @@ async function testDatabaseDeploy(engine, conn, driver, dbModelsYaml, options) {
dbdiffOptionsExtra.schemaMode = 'ignore';
for (const loadedDbModel of dbModelsYaml) {
const { sql, isEmpty } = await generateDeploySql({
systemConnection: conn.isPreparedOnly ? undefined : conn,
connection: conn.isPreparedOnly ? conn : undefined,
driver,
loadedDbModel,
dbdiffOptionsExtra,
});
console.debug('Generated deploy script:', sql);
if (!allowDropStatements) {
expect(sql.toUpperCase().includes('DROP ')).toBeFalsy();
}
if (_.isString(loadedDbModel)) {
await driver.script(conn, formatQueryWithoutParams(driver, loadedDbModel));
} else {
const { sql, isEmpty } = await generateDeploySql({
systemConnection: conn.isPreparedOnly ? undefined : conn,
connection: conn.isPreparedOnly ? conn : undefined,
driver,
loadedDbModel: convertModelToEngine(loadedDbModel, driver),
dbdiffOptionsExtra,
});
console.debug('Generated deploy script:', sql);
if (!allowDropStatements) {
expect(sql.toUpperCase().includes('DROP ')).toBeFalsy();
}
console.log('dbModelsYaml.length', dbModelsYaml.length, index);
if (testEmptyLastScript && index == dbModelsYaml.length - 1) {
expect(isEmpty).toBeTruthy();
}
console.log('dbModelsYaml.length', dbModelsYaml.length, index);
if (testEmptyLastScript && index == dbModelsYaml.length - 1) {
expect(isEmpty).toBeTruthy();
}
await deployDb({
systemConnection: conn.isPreparedOnly ? undefined : conn,
connection: conn.isPreparedOnly ? conn : undefined,
driver,
loadedDbModel,
dbdiffOptionsExtra,
});
await deployDb({
systemConnection: conn.isPreparedOnly ? undefined : conn,
connection: conn.isPreparedOnly ? conn : undefined,
driver,
loadedDbModel: convertModelToEngine(loadedDbModel, driver),
dbdiffOptionsExtra,
});
}
index++;
}
@@ -113,7 +140,12 @@ async function testDatabaseDeploy(engine, conn, driver, dbModelsYaml, options) {
const dbhan = conn.isPreparedOnly ? await connectUtility(driver, conn, 'read') : conn;
const structure = await driver.analyseFull(dbhan);
if (conn.isPreparedOnly) await driver.close(dbhan);
checkStructure(engine, structure, finalCheckAgainstModel ?? dbModelsYaml[dbModelsYaml.length - 1], options);
checkStructure(
engine,
structure,
convertModelToEngine(finalCheckAgainstModel ?? _.findLast(dbModelsYaml, x => _.isArray(x)), driver),
options
);
}
describe('Deploy database', () => {
@@ -335,7 +367,7 @@ describe('Deploy database', () => {
],
]);
const res = await driver.query(conn, `select count(*) as cnt from t1`);
const res = await runQueryOnDriver(conn, driver, `select count(*) as ~cnt from ~t1`);
expect(res.rows[0].cnt.toString()).toEqual('3');
})
);
@@ -382,12 +414,12 @@ describe('Deploy database', () => {
],
]);
const res = await driver.query(conn, `select val from t1 where id = 2`);
const res = await runQueryOnDriver(conn, driver, `select ~val from ~t1 where ~id = 2`);
expect(res.rows[0].val.toString()).toEqual('5');
})
);
test.each(engines.enginesPostgre.map(engine => [engine.label, engine]))(
test.each([engines.postgreSqlEngine].map(engine => [engine.label, engine]))(
'Current timestamp default value - %s',
testWrapper(async (conn, driver, engine) => {
await testDatabaseDeploy(engine, conn, driver, [
@@ -410,12 +442,58 @@ describe('Deploy database', () => {
],
]);
await driver.query(conn, `insert into t1 (id) values (1)`);
const res = await driver.query(conn, ` select val from t1 where id = 1`);
await runQueryOnDriver(conn, driver, `insert into ~t1 (~id) values (1)`);
const res = await runQueryOnDriver(conn, driver, ` select ~val from ~t1 where ~id = 1`);
expect(res.rows[0].val.toString().substring(0, 2)).toEqual('20');
})
);
test.each(engines.filter(x => !x.skipChangeColumn).map(engine => [engine.label, engine]))(
'Change column to NOT NULL column with default - %s',
testWrapper(async (conn, driver, engine) => {
await testDatabaseDeploy(engine, conn, driver, [
[
{
name: 't1.table.yaml',
json: {
name: 't1',
columns: [
{ name: 'id', type: 'int', notNull: true },
{ name: 'val', type: 'int' },
],
primaryKey: ['id'],
},
},
],
'insert into ~t1 (~id, ~val) values (1, 1); insert into ~t1 (~id) values (2)',
[
{
name: 't1.table.yaml',
json: {
name: 't1',
columns: [
{ name: 'id', type: 'int', notNull: true },
{ name: 'val', type: 'int', notNull: true, default: '20' },
],
primaryKey: ['id'],
},
},
],
'insert into ~t1 (~id) values (3);',
]);
const res1 = await runQueryOnDriver(conn, driver, `select ~val from ~t1 where ~id = 1`);
expect(res1.rows[0].val).toEqual(1);
const res2 = await runQueryOnDriver(conn, driver, `select ~val from ~t1 where ~id = 2`);
expect(res2.rows[0].val).toEqual(20);
const res3 = await runQueryOnDriver(conn, driver, `select ~val from ~t1 where ~id = 3`);
expect(res2.rows[0].val).toEqual(20);
})
);
const T1 = {
name: 't1.table.yaml',
json: {
@@ -428,6 +506,18 @@ describe('Deploy database', () => {
},
};
const T2 = {
name: 't2.table.yaml',
json: {
name: 't2',
columns: [
{ name: 'id', type: 'int' },
{ name: 'val', type: 'int' },
],
primaryKey: ['id'],
},
};
const T1_DELETED = {
name: '_deleted_t1.table.yaml',
json: {
@@ -463,17 +553,17 @@ describe('Deploy database', () => {
const V1 = {
name: 'v1.view.sql',
text: 'create view v1 as select * from t1',
text: 'create view ~v1 as select * from ~t1',
};
const V1_VARIANT2 = {
name: 'v1.view.sql',
text: 'create view v1 as select 1 as c1',
text: 'create view ~v1 as select ~id + ~id ~idsum from ~t1',
};
const V1_DELETED = {
name: '_deleted_v1.view.sql',
text: 'create view _deleted_v1 as select * from t1',
text: 'create view ~_deleted_v1 as select * from ~t1',
};
test.each(engines.map(engine => [engine.label, engine]))(
@@ -620,15 +710,15 @@ describe('Deploy database', () => {
[
{
name: '1.predeploy.sql',
text: 'create table t1 (id int primary key); insert into t1 (id) values (1);',
text: 'create table ~t1 (~id int primary key); insert into ~t1 (~id) values (1);',
},
],
]);
const res1 = await driver.query(conn, 'SELECT COUNT(*) AS cnt FROM t1');
const res1 = await runQueryOnDriver(conn, driver, 'SELECT COUNT(*) AS ~cnt FROM ~t1');
expect(res1.rows[0].cnt == 1).toBeTruthy();
const res2 = await driver.query(conn, 'SELECT COUNT(*) AS cnt FROM dbgate_deploy_journal');
const res2 = await runQueryOnDriver(conn, driver, 'SELECT COUNT(*) AS ~cnt FROM ~dbgate_deploy_journal');
expect(res2.rows[0].cnt == 1).toBeTruthy();
})
);
@@ -640,50 +730,66 @@ describe('Deploy database', () => {
[
{
name: 't1.uninstall.sql',
text: 'drop table t1',
text: 'drop table ~t1',
},
{
name: 't1.install.sql',
text: 'create table t1 (id int primary key); insert into t1 (id) values (1)',
text: 'create table ~t1 (~id int primary key); insert into ~t1 (~id) values (1)',
},
{
name: 't2.once.sql',
text: 'create table t2 (id int primary key); insert into t2 (id) values (1)',
text: 'create table ~t2 (~id int primary key); insert into ~t2 (~id) values (1)',
},
],
[
{
name: 't1.uninstall.sql',
text: 'drop table t1',
text: 'drop table ~t1',
},
{
name: 't1.install.sql',
text: 'create table t1 (id int primary key, val int); insert into t1 (id, val) values (1, 11)',
text: 'create table ~t1 (~id int primary key, ~val int); insert into ~t1 (~id, ~val) values (1, 11)',
},
{
name: 't2.once.sql',
text: 'insert into t2 (id) values (2)',
text: 'insert into ~t2 (~id) values (2)',
},
],
]);
const res1 = await driver.query(conn, 'SELECT val from t1 where id = 1');
const res1 = await runQueryOnDriver(conn, driver, 'SELECT ~val from ~t1 where ~id = 1');
expect(res1.rows[0].val == 11).toBeTruthy();
const res2 = await driver.query(conn, 'SELECT COUNT(*) AS cnt FROM t2');
const res2 = await runQueryOnDriver(conn, driver, 'SELECT COUNT(*) AS ~cnt FROM ~t2');
expect(res2.rows[0].cnt == 1).toBeTruthy();
const res3 = await driver.query(conn, 'SELECT COUNT(*) AS cnt FROM dbgate_deploy_journal');
const res3 = await runQueryOnDriver(conn, driver, 'SELECT COUNT(*) AS ~cnt FROM ~dbgate_deploy_journal');
expect(res3.rows[0].cnt == 3).toBeTruthy();
const res4 = await driver.query(conn, "SELECT run_count from dbgate_deploy_journal where name = 't2.once.sql'");
const res4 = await runQueryOnDriver(
conn,
driver,
"SELECT ~run_count from ~dbgate_deploy_journal where ~name = 't2.once.sql'"
);
expect(res4.rows[0].run_count == 1).toBeTruthy();
const res5 = await driver.query(
const res5 = await runQueryOnDriver(
conn,
"SELECT run_count from dbgate_deploy_journal where name = 't1.install.sql'"
driver,
"SELECT ~run_count from ~dbgate_deploy_journal where ~name = 't1.install.sql'"
);
expect(res5.rows[0].run_count == 2).toBeTruthy();
})
);
test.each(engines.map(engine => [engine.label, engine]))(
'Mark table removed, one remains - %s',
testWrapper(async (conn, driver, engine) => {
await testDatabaseDeploy(engine, conn, driver, [[T1, T2], [T2], [T2]], {
markDeleted: true,
disallowExtraObjects: true,
finalCheckAgainstModel: [T1_DELETED, T2],
});
})
);
});

View File

@@ -1,8 +1,9 @@
const { testWrapper } = require('../tools');
const engines = require('../engines');
const _ = require('lodash');
const { formatQueryWithoutParams, runCommandOnDriver } = require('dbgate-tools');
const initSql = ['CREATE TABLE t1 (id int primary key)', 'CREATE TABLE t2 (id int primary key)'];
const initSql = ['CREATE TABLE ~t1 (~id int primary key)', 'CREATE TABLE ~t2 (~id int primary key)'];
function flatSource() {
return _.flatten(
@@ -10,6 +11,24 @@ function flatSource() {
);
}
function flatSourceParameters() {
return _.flatten(
engines.map(engine =>
(engine.parameters || []).map(parameter => [engine.label, parameter.testName, parameter, engine])
)
);
}
function flatSourceTriggers() {
return _.flatten(engines.map(engine => (engine.triggers || []).map(trigger => [engine.label, trigger, engine])));
}
function flatSourceSchedulerEvents() {
return _.flatten(
engines.map(engine => (engine.schedulerEvents || []).map(schedulerEvent => [engine.label, schedulerEvent, engine]))
);
}
const obj1Match = expect.objectContaining({
pureName: 'obj1',
});
@@ -26,9 +45,9 @@ describe('Object analyse', () => {
test.each(flatSource())(
'Full analysis - %s - %s',
testWrapper(async (conn, driver, type, object, engine) => {
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
for (const sql of initSql) await runCommandOnDriver(conn, driver, sql);
await driver.query(conn, object.create1, { discardResult: true });
await runCommandOnDriver(conn, driver, object.create1);
const structure = await driver.analyseFull(conn);
expect(structure[type].length).toEqual(1);
@@ -39,11 +58,11 @@ describe('Object analyse', () => {
test.each(flatSource())(
'Incremental analysis - add - %s - %s',
testWrapper(async (conn, driver, type, object, engine) => {
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
for (const sql of initSql) await runCommandOnDriver(conn, driver, sql);
await driver.query(conn, object.create2, { discardResult: true });
await runCommandOnDriver(conn, driver, object.create2);
const structure1 = await driver.analyseFull(conn);
await driver.query(conn, object.create1, { discardResult: true });
await runCommandOnDriver(conn, driver, object.create1);
const structure2 = await driver.analyseIncremental(conn, structure1);
expect(structure2[type].length).toEqual(2);
@@ -54,12 +73,12 @@ describe('Object analyse', () => {
test.each(flatSource())(
'Incremental analysis - drop - %s - %s',
testWrapper(async (conn, driver, type, object, engine) => {
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
for (const sql of initSql) await runCommandOnDriver(conn, driver, sql);
await driver.query(conn, object.create1, { discardResult: true });
await driver.query(conn, object.create2, { discardResult: true });
await runCommandOnDriver(conn, driver, object.create1);
await runCommandOnDriver(conn, driver, object.create2);
const structure1 = await driver.analyseFull(conn);
await driver.query(conn, object.drop2, { discardResult: true });
await runCommandOnDriver(conn, driver, object.drop2);
const structure2 = await driver.analyseIncremental(conn, structure1);
expect(structure2[type].length).toEqual(1);
@@ -70,15 +89,15 @@ describe('Object analyse', () => {
test.each(flatSource())(
'Create SQL - add - %s - %s',
testWrapper(async (conn, driver, type, object, engine) => {
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
for (const sql of initSql) await runCommandOnDriver(conn, driver, sql);
await driver.query(conn, object.create1, { discardResult: true });
await runCommandOnDriver(conn, driver, object.create1);
const structure1 = await driver.analyseFull(conn);
await driver.query(conn, object.drop1, { discardResult: true });
await runCommandOnDriver(conn, driver, object.drop1);
const structure2 = await driver.analyseIncremental(conn, structure1);
expect(structure2[type].length).toEqual(0);
await driver.query(conn, structure1[type][0].createSql, { discardResult: true });
await driver.script(conn, structure1[type][0].createSql);
const structure3 = await driver.analyseIncremental(conn, structure2);
@@ -86,4 +105,95 @@ describe('Object analyse', () => {
expect(structure3[type][0]).toEqual(type.includes('views') ? view1Match : obj1Match);
})
);
const flatParameters = flatSourceParameters();
if (flatParameters.length > 0) {
test.each(flatParameters)(
'Test parameters simple analyse - %s - %s',
testWrapper(async (conn, driver, testName, parameter, engine) => {
for (const sql of initSql) await runCommandOnDriver(conn, driver, sql);
for (const sql of engine.parametersOtherSql) await runCommandOnDriver(conn, driver, sql);
await runCommandOnDriver(conn, driver, parameter.create);
const structure = await driver.analyseFull(conn);
const parameters = structure[parameter.objectTypeField].find(x => x.pureName == 'obj1').parameters;
expect(parameters.length).toEqual(parameter.list.length);
for (let i = 0; i < parameters.length; i += 1) {
expect(parameters[i]).toEqual(expect.objectContaining(parameter.list[i]));
}
})
);
test.each(flatParameters)(
'Test parameters create SQL - %s - %s',
testWrapper(async (conn, driver, testName, parameter, engine) => {
for (const sql of initSql) await runCommandOnDriver(conn, driver, sql);
for (const sql of engine.parametersOtherSql) await runCommandOnDriver(conn, driver, sql);
await runCommandOnDriver(conn, driver, parameter.create);
const structure1 = await driver.analyseFull(conn);
await runCommandOnDriver(conn, driver, parameter.drop);
const obj = structure1[parameter.objectTypeField].find(x => x.pureName == 'obj1');
await driver.script(conn, obj.createSql, { discardResult: true });
const structure2 = await driver.analyseFull(conn);
const parameters = structure2[parameter.objectTypeField].find(x => x.pureName == 'obj1').parameters;
expect(parameters.length).toEqual(parameter.list.length);
for (let i = 0; i < parameters.length; i += 1) {
expect(parameters[i]).toEqual(expect.objectContaining(parameter.list[i]));
}
})
);
}
test.each(flatSourceTriggers())(
'Test triggers - %s - %s',
testWrapper(async (conn, driver, trigger) => {
for (const sql of initSql) await runCommandOnDriver(conn, driver, sql);
const { triggerOtherDropSql, triggerOtherCreateSql, create, drop, expected, objectTypeField } = trigger;
if (triggerOtherCreateSql) await runCommandOnDriver(conn, driver, triggerOtherCreateSql);
await runCommandOnDriver(conn, driver, create);
const structure = await driver.analyseFull(conn);
await runCommandOnDriver(conn, driver, drop);
if (triggerOtherDropSql) await runCommandOnDriver(conn, driver, triggerOtherDropSql);
const createdTrigger = structure[objectTypeField].find(x => x.pureName == expected.pureName);
expect(createdTrigger).toEqual(expect.objectContaining(expected));
// test trigger createSql
if (triggerOtherCreateSql) await runCommandOnDriver(conn, driver, triggerOtherCreateSql);
await driver.script(conn, createdTrigger.createSql);
const structure2 = await driver.analyseFull(conn);
const createdTrigger2 = structure2[objectTypeField].find(x => x.pureName == expected.pureName);
expect(createdTrigger2).toEqual(expect.objectContaining(expected));
})
);
const schedulerEvents = flatSourceSchedulerEvents();
if (schedulerEvents.length > 0) {
test.each(schedulerEvents)(
'Test scheduler events - %s - %s',
testWrapper(async (conn, driver, event) => {
for (const sql of initSql) await runCommandOnDriver(conn, driver, sql);
const { create, drop, objectTypeField, expected } = event;
await runCommandOnDriver(conn, driver, create);
const structure = await driver.analyseFull(conn);
await runCommandOnDriver(conn, driver, drop);
const createdEvent = structure[objectTypeField].find(x => x.pureName == expected.pureName);
expect(createdEvent).toEqual(expect.objectContaining(expected));
})
);
}
});

View File

@@ -1,11 +1,12 @@
const engines = require('../engines');
const { splitQuery } = require('dbgate-query-splitter');
const { testWrapper } = require('../tools');
const { runQueryOnDriver, runCommandOnDriver, formatQueryWithoutParams } = require('dbgate-tools');
const initSql = [
'CREATE TABLE t1 (id int primary key)',
'INSERT INTO t1 (id) VALUES (1)',
'INSERT INTO t1 (id) VALUES (2)',
'CREATE TABLE ~t1 (~id int primary key)',
'INSERT INTO ~t1 (~id) VALUES (1)',
'INSERT INTO ~t1 (~id) VALUES (2)',
];
expect.extend({
@@ -51,7 +52,7 @@ class StreamHandler {
function executeStreamItem(driver, conn, sql) {
return new Promise(resolve => {
const handler = new StreamHandler(resolve);
driver.stream(conn, sql, handler);
driver.stream(conn, formatQueryWithoutParams(driver, sql), handler);
});
}
@@ -68,9 +69,11 @@ describe('Query', () => {
test.each(engines.map(engine => [engine.label, engine]))(
'Simple query - %s',
testWrapper(async (conn, driver, engine) => {
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
for (const sql of initSql) {
await runCommandOnDriver(conn, driver, dmp => dmp.put(sql));
}
const res = await driver.query(conn, 'SELECT id FROM t1 ORDER BY id');
const res = await runQueryOnDriver(conn, driver, dmp => dmp.put('SELECT ~id FROM ~t1 ORDER BY ~id'));
expect(res.columns).toEqual([
expect.objectContaining({
columnName: 'id',
@@ -91,8 +94,11 @@ describe('Query', () => {
test.each(engines.map(engine => [engine.label, engine]))(
'Simple stream query - %s',
testWrapper(async (conn, driver, engine) => {
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
const results = await executeStream(driver, conn, 'SELECT id FROM t1 ORDER BY id');
for (const sql of initSql) {
await runCommandOnDriver(conn, driver, dmp => dmp.put(sql));
}
const results = await executeStream(driver, conn, 'SELECT ~id FROM ~t1 ORDER BY ~id');
expect(results.length).toEqual(1);
const res = results[0];
@@ -104,11 +110,14 @@ describe('Query', () => {
test.each(engines.map(engine => [engine.label, engine]))(
'More queries - %s',
testWrapper(async (conn, driver, engine) => {
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
for (const sql of initSql) {
await runCommandOnDriver(conn, driver, dmp => dmp.put(sql));
}
const results = await executeStream(
driver,
conn,
'SELECT id FROM t1 ORDER BY id; SELECT id FROM t1 ORDER BY id DESC'
'SELECT ~id FROM ~t1 ORDER BY ~id; SELECT ~id FROM ~t1 ORDER BY ~id DESC'
);
expect(results.length).toEqual(2);
@@ -128,7 +137,7 @@ describe('Query', () => {
const results = await executeStream(
driver,
conn,
'CREATE TABLE t1 (id int primary key); INSERT INTO t1 (id) VALUES (1); INSERT INTO t1 (id) VALUES (2); SELECT id FROM t1 ORDER BY id; '
'CREATE TABLE ~t1 (~id int primary key); INSERT INTO ~t1 (~id) VALUES (1); INSERT INTO ~t1 (~id) VALUES (2); SELECT ~id FROM ~t1 ORDER BY ~id; '
);
expect(results.length).toEqual(1);
@@ -144,7 +153,7 @@ describe('Query', () => {
const results = await executeStream(
driver,
conn,
'CREATE TABLE t1 (id int); INSERT INTO t1 (id) VALUES (1); INSERT INTO t1 (id) VALUES (2) '
'CREATE TABLE ~t1 (~id int); INSERT INTO ~t1 (~id) VALUES (1); INSERT INTO ~t1 (~id) VALUES (2) '
);
expect(results.length).toEqual(0);
})
@@ -153,16 +162,57 @@ describe('Query', () => {
test.each(engines.filter(x => !x.skipDataModifications).map(engine => [engine.label, engine]))(
'Save data query - %s',
testWrapper(async (conn, driver, engine) => {
for (const sql of initSql) await driver.query(conn, sql, { discardResult: true });
for (const sql of initSql) {
await runCommandOnDriver(conn, driver, dmp => dmp.put(sql));
}
await driver.script(
conn,
'INSERT INTO t1 (id) VALUES (3);INSERT INTO t1 (id) VALUES (4);UPDATE t1 SET id=10 WHERE id=1;DELETE FROM t1 WHERE id=2;',
formatQueryWithoutParams(
driver,
'INSERT INTO ~t1 (~id) VALUES (3);INSERT INTO ~t1 (~id) VALUES (4);UPDATE ~t1 SET ~id=10 WHERE ~id=1;DELETE FROM ~t1 WHERE ~id=2;'
),
{ discardResult: true }
);
const res = await driver.query(conn, 'SELECT COUNT(*) AS cnt FROM t1');
const res = await runQueryOnDriver(conn, driver, dmp => dmp.put('SELECT COUNT(*) AS ~cnt FROM ~t1'));
// console.log(res);
expect(res.rows[0].cnt == 3).toBeTruthy();
})
);
test.each(engines.filter(x => !x.skipDataDuplicator).map(engine => [engine.label, engine]))(
'Select scope identity - %s',
testWrapper(async (conn, driver, engine) => {
await runCommandOnDriver(conn, driver, dmp =>
dmp.createTable({
pureName: 't1',
columns: [
{ columnName: 'id', dataType: 'int', notNull: true, autoIncrement: true },
{ columnName: 'val', dataType: 'varchar(50)' },
],
primaryKey: {
columns: [{ columnName: 'id' }],
},
})
);
const structure = await driver.analyseFull(conn);
const table = structure.tables.find(x => x.pureName == 't1');
let res;
if (driver.dialect.requireStandaloneSelectForScopeIdentity) {
await runCommandOnDriver(conn, driver, dmp => dmp.put("INSERT INTO ~t1 (~val) VALUES ('aaa')"));
res = await runQueryOnDriver(conn, driver, dmp => dmp.selectScopeIdentity(table));
} else {
res = await runQueryOnDriver(conn, driver, dmp => {
dmp.putCmd("INSERT INTO ~t1 (~val) VALUES ('aaa')");
dmp.selectScopeIdentity(table);
});
}
const row = res.rows[0];
const keys = Object.keys(row);
expect(keys.length).toEqual(1);
expect(row[keys[0]] == 1).toBeTruthy();
})
);
});

View File

@@ -1,7 +1,7 @@
const stableStringify = require('json-stable-stringify');
const _ = require('lodash');
const fp = require('lodash/fp');
const { testWrapper, extractConnection } = require('../tools');
const { testWrapper } = require('../tools');
const engines = require('../engines');
const { runCommandOnDriver } = require('dbgate-tools');
@@ -62,7 +62,7 @@ describe('Schema tests', () => {
await runCommandOnDriver(handle, driver, dmp => dmp.createSchema('myschema'));
const schemaConnDef = {
...extractConnection(engine),
...engine.connection,
database: `${handle.database}::myschema`,
};
@@ -76,7 +76,7 @@ describe('Schema tests', () => {
});
describe('Base analyser test', () => {
test.each(engines.map(engine => [engine.label, engine]))(
test.each(engines.filter(x => !x.skipIncrementalAnalysis).map(engine => [engine.label, engine]))(
'Structure without change - %s',
testWrapper(async (conn, driver, engine) => {
await baseStructure(conn, driver);

View File

@@ -1,12 +1,13 @@
const { runCommandOnDriver } = require('dbgate-tools');
const engines = require('../engines');
const { testWrapper } = require('../tools');
const t1Sql = 'CREATE TABLE t1 (id int not null primary key, val1 varchar(50))';
const ix1Sql = 'CREATE index ix1 ON t1(val1, id)';
const t1Sql = 'CREATE TABLE ~t1 (~id int not null primary key, ~val1 varchar(50))';
const ix1Sql = 'CREATE index ~ix1 ON ~t1(~val1, ~id)';
const t2Sql = engine =>
`CREATE TABLE t2 (id int not null primary key, val2 varchar(50) ${engine.skipUnique ? '' : 'unique'})`;
const t3Sql = 'CREATE TABLE t3 (id int not null primary key, valfk int, foreign key (valfk) references t2(id))';
const t4Sql = 'CREATE TABLE t4 (id int not null primary key, valdef int not null default 12)';
`CREATE TABLE ~t2 (~id int not null primary key, ~val2 varchar(50) ${engine.skipUnique ? '' : 'unique'})`;
const t3Sql = 'CREATE TABLE ~t3 (~id int not null primary key, ~valfk int, foreign key (~valfk) references ~t2(~id))';
const t4Sql = 'CREATE TABLE ~t4 (~id int not null primary key, ~valdef int default 12 not null)';
// const fkSql = 'ALTER TABLE t3 ADD FOREIGN KEY (valfk) REFERENCES t2(id)'
const txMatch = (engine, tname, vcolname, nextcol, defaultValue) =>
@@ -15,7 +16,7 @@ const txMatch = (engine, tname, vcolname, nextcol, defaultValue) =>
columns: [
expect.objectContaining({
columnName: 'id',
dataType: expect.stringMatching(/int.*/i),
dataType: expect.stringMatching(/int.*|number/i),
...(engine.skipNullability ? {} : { notNull: true }),
}),
expect.objectContaining({
@@ -59,9 +60,10 @@ describe('Table analyse', () => {
test.each(engines.map(engine => [engine.label, engine]))(
'Table structure - full analysis - %s',
testWrapper(async (conn, driver, engine) => {
await driver.query(conn, t1Sql);
await runCommandOnDriver(conn, driver, dmp => dmp.put(t1Sql));
const structure = await driver.analyseFull(conn);
console.log(JSON.stringify(structure, null, 2));
expect(structure.tables.length).toEqual(1);
expect(structure.tables[0]).toEqual(t1Match(engine));
@@ -71,13 +73,13 @@ describe('Table analyse', () => {
test.each(engines.map(engine => [engine.label, engine]))(
'Table add - incremental analysis - %s',
testWrapper(async (conn, driver, engine) => {
await driver.query(conn, t2Sql(engine));
await runCommandOnDriver(conn, driver, dmp => dmp.put(t2Sql(engine)));
const structure1 = await driver.analyseFull(conn);
expect(structure1.tables.length).toEqual(1);
expect(structure1.tables[0]).toEqual(t2Match(engine));
await driver.query(conn, t1Sql);
await runCommandOnDriver(conn, driver, dmp => dmp.put(t1Sql));
const structure2 = await driver.analyseIncremental(conn, structure1);
expect(structure2.tables.length).toEqual(2);
@@ -89,14 +91,14 @@ describe('Table analyse', () => {
test.each(engines.map(engine => [engine.label, engine]))(
'Table remove - incremental analysis - %s',
testWrapper(async (conn, driver, engine) => {
await driver.query(conn, t1Sql);
await driver.query(conn, t2Sql(engine));
await runCommandOnDriver(conn, driver, dmp => dmp.put(t1Sql));
await runCommandOnDriver(conn, driver, dmp => dmp.put(t2Sql(engine)));
const structure1 = await driver.analyseFull(conn);
expect(structure1.tables.length).toEqual(2);
expect(structure1.tables.find(x => x.pureName == 't1')).toEqual(t1Match(engine));
expect(structure1.tables.find(x => x.pureName == 't2')).toEqual(t2Match(engine));
await driver.query(conn, 'DROP TABLE t2');
await runCommandOnDriver(conn, driver, dmp => dmp.put('DROP TABLE ~t2'));
const structure2 = await driver.analyseIncremental(conn, structure1);
expect(structure2.tables.length).toEqual(1);
@@ -107,15 +109,14 @@ describe('Table analyse', () => {
test.each(engines.map(engine => [engine.label, engine]))(
'Table change - incremental analysis - %s',
testWrapper(async (conn, driver, engine) => {
await driver.query(conn, t1Sql);
await driver.query(conn, t2Sql(engine));
await runCommandOnDriver(conn, driver, dmp => dmp.put(t1Sql));
await runCommandOnDriver(conn, driver, dmp => dmp.put(t2Sql(engine)));
const structure1 = await driver.analyseFull(conn);
if (engine.dbSnapshotBySeconds) await new Promise(resolve => setTimeout(resolve, 1100));
await driver.query(
conn,
`ALTER TABLE t2 ADD ${engine.alterTableAddColumnSyntax ? 'COLUMN' : ''} nextcol varchar(50)`
await runCommandOnDriver(conn, driver, dmp =>
dmp.put(`ALTER TABLE ~t2 ADD ${engine.alterTableAddColumnSyntax ? 'COLUMN' : ''} ~nextcol varchar(50)`)
);
const structure2 = await driver.analyseIncremental(conn, structure1);
@@ -130,8 +131,8 @@ describe('Table analyse', () => {
test.each(engines.filter(x => !x.skipIndexes).map(engine => [engine.label, engine]))(
'Index - full analysis - %s',
testWrapper(async (conn, driver, engine) => {
await driver.query(conn, t1Sql);
await driver.query(conn, ix1Sql);
await runCommandOnDriver(conn, driver, dmp => dmp.put(t1Sql));
await runCommandOnDriver(conn, driver, dmp => dmp.put(ix1Sql));
const structure = await driver.analyseFull(conn);
const t1 = structure.tables.find(x => x.pureName == 't1');
@@ -145,7 +146,7 @@ describe('Table analyse', () => {
test.each(engines.filter(x => !x.skipUnique).map(engine => [engine.label, engine]))(
'Unique - full analysis - %s',
testWrapper(async (conn, driver, engine) => {
await driver.query(conn, t2Sql(engine));
await runCommandOnDriver(conn, driver, dmp => dmp.put(t2Sql(engine)));
const structure = await driver.analyseFull(conn);
const t2 = structure.tables.find(x => x.pureName == 't2');
@@ -159,8 +160,8 @@ describe('Table analyse', () => {
test.each(engines.filter(x => !x.skipReferences).map(engine => [engine.label, engine]))(
'Foreign key - full analysis - %s',
testWrapper(async (conn, driver, engine) => {
await driver.query(conn, t2Sql(engine));
await driver.query(conn, t3Sql);
await runCommandOnDriver(conn, driver, dmp => dmp.put(t2Sql(engine)));
await runCommandOnDriver(conn, driver, dmp => dmp.put(t3Sql));
// await driver.query(conn, fkSql);
const structure = await driver.analyseFull(conn);
@@ -179,7 +180,7 @@ describe('Table analyse', () => {
test.each(engines.map(engine => [engine.label, engine]))(
'Table structure - default value - %s',
testWrapper(async (conn, driver, engine) => {
await driver.query(conn, t4Sql);
await runCommandOnDriver(conn, driver, dmp => dmp.put(t4Sql));
const structure = await driver.analyseFull(conn);

View File

@@ -2,7 +2,7 @@ const _ = require('lodash');
const fp = require('lodash/fp');
const engines = require('../engines');
const { testWrapper } = require('../tools');
const { extendDatabaseInfo } = require('dbgate-tools');
const { extendDatabaseInfo, runCommandOnDriver } = require('dbgate-tools');
function createExpector(value) {
return _.cloneDeepWith(value, x => {
@@ -25,7 +25,7 @@ function checkTableStructure2(t1, t2) {
}
async function testTableCreate(conn, driver, table) {
await driver.query(conn, `create table t0 (id int not null primary key)`);
await runCommandOnDriver(conn, driver, dmp => dmp.put('create table ~t0 (~id int not null primary key)'));
const dmp = driver.createDumper();
const table1 = {

View File

@@ -70,3 +70,9 @@ services:
# - cockroachdb
# restart: on-failure
oracle:
image: gvenzl/oracle-xe:21-slim
environment:
ORACLE_PASSWORD: Pwd2020Db
ports:
- 15006:1521

View File

@@ -1,9 +1,9 @@
const views = {
type: 'views',
create1: 'CREATE VIEW obj1 AS SELECT id FROM t1',
create2: 'CREATE VIEW obj2 AS SELECT id FROM t2',
drop1: 'DROP VIEW obj1',
drop2: 'DROP VIEW obj2',
create1: 'CREATE VIEW ~obj1 AS SELECT ~id FROM ~t1',
create2: 'CREATE VIEW ~obj2 AS SELECT ~id FROM ~t2',
drop1: 'DROP VIEW ~obj1',
drop2: 'DROP VIEW ~obj2',
};
const matviews = {
type: 'matviews',
@@ -13,192 +13,616 @@ const matviews = {
drop2: 'DROP MATERIALIZED VIEW obj2',
};
const engines = [
{
label: 'MySQL',
connection: {
engine: 'mysql@dbgate-plugin-mysql',
password: 'Pwd2020Db',
user: 'root',
server: 'mysql',
port: 3306,
const mysqlEngine = {
label: 'MySQL',
connection: {
engine: 'mysql@dbgate-plugin-mysql',
password: 'Pwd2020Db',
user: 'root',
server: 'localhost',
port: 15001,
},
objects: [
views,
{
type: 'schedulerEvents',
create1: 'CREATE EVENT obj1 ON SCHEDULE EVERY 1 HOUR DO BEGIN END',
create2: 'CREATE EVENT obj2 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY DO BEGIN END',
drop1: 'DROP EVENT obj1',
drop2: 'DROP EVENT obj2',
},
local: {
server: 'localhost',
port: 15001,
{
type: 'procedures',
create1: 'CREATE PROCEDURE obj1() BEGIN SELECT * FROM t1; END',
create2: 'CREATE PROCEDURE obj2() BEGIN SELECT * FROM t2; END',
drop1: 'DROP PROCEDURE obj1',
drop2: 'DROP PROCEDURE obj2',
},
// skipOnCI: true,
objects: [views],
dbSnapshotBySeconds: true,
dumpFile: 'data/chinook-mysql.sql',
dumpChecks: [
{
sql: 'select count(*) as res from genre',
res: '25',
],
supportRenameSqlObject: false,
dbSnapshotBySeconds: true,
dumpFile: 'data/chinook-mysql.sql',
dumpChecks: [
{
sql: 'select count(*) as res from genre',
res: '25',
},
],
parametersOtherSql: ['CREATE PROCEDURE obj2(a int, b int) BEGIN SELECT * FROM t1; END'],
parameters: [
{
testName: 'simple',
create: 'CREATE PROCEDURE obj1(a int) BEGIN SELECT * FROM t1; END',
drop: 'DROP PROCEDURE obj1',
objectTypeField: 'procedures',
list: [
{
parameterName: 'a',
parameterMode: 'IN',
dataType: 'int',
},
],
},
{
testName: 'paramTypes',
create: 'CREATE PROCEDURE obj1(a int, b varchar(50), c numeric(10,2)) BEGIN SELECT * FROM t1; END',
drop: 'DROP PROCEDURE obj1',
objectTypeField: 'procedures',
list: [
{
parameterName: 'a',
parameterMode: 'IN',
dataType: 'int',
},
{
parameterName: 'b',
parameterMode: 'IN',
dataType: 'varchar(50)',
},
{
parameterName: 'c',
parameterMode: 'IN',
dataType: 'decimal(10,2)',
},
],
},
{
testName: 'paramModes',
create: 'CREATE PROCEDURE obj1(IN a int, OUT b int, INOUT c int) BEGIN SELECT * FROM t1; END',
drop: 'DROP PROCEDURE obj1',
objectTypeField: 'procedures',
list: [
{
parameterName: 'a',
parameterMode: 'IN',
dataType: 'int',
},
{
parameterName: 'b',
parameterMode: 'OUT',
dataType: 'int',
},
{
parameterName: 'c',
parameterMode: 'INOUT',
dataType: 'int',
},
],
},
],
triggers: [
{
testName: 'triggers insert after',
create: 'CREATE TRIGGER obj1 AFTER INSERT ON t1 FOR EACH ROW BEGIN END',
drop: 'DROP TRIGGER obj1;',
objectTypeField: 'triggers',
expected: {
pureName: 'obj1',
eventType: 'INSERT',
triggerTiming: 'AFTER',
},
],
},
{
label: 'MariaDB',
connection: {
engine: 'mariadb@dbgate-plugin-mysql',
password: 'Pwd2020Db',
user: 'root',
server: 'mysql',
port: 3306,
},
local: {
server: 'localhost',
port: 15004,
},
skipOnCI: true,
objects: [views],
dbSnapshotBySeconds: true,
dumpFile: 'data/chinook-mysql.sql',
dumpChecks: [
{
sql: 'select count(*) as res from genre',
res: '25',
{
testName: 'triggers insert before',
create: 'CREATE TRIGGER obj1 BEFORE INSERT ON t1 FOR EACH ROW BEGIN END',
drop: 'DROP TRIGGER obj1;',
objectTypeField: 'triggers',
expected: {
pureName: 'obj1',
eventType: 'INSERT',
triggerTiming: 'BEFORE',
},
],
},
{
label: 'PostgreSQL',
connection: {
engine: 'postgres@dbgate-plugin-postgres',
password: 'Pwd2020Db',
user: 'postgres',
server: 'postgres',
port: 5432,
},
local: {
server: 'localhost',
port: 15000,
},
objects: [
views,
matviews,
{
type: 'procedures',
create1: 'CREATE PROCEDURE obj1() LANGUAGE SQL AS $$ select * from t1 $$',
create2: 'CREATE PROCEDURE obj2() LANGUAGE SQL AS $$ select * from t2 $$',
drop1: 'DROP PROCEDURE obj1',
drop2: 'DROP PROCEDURE obj2',
],
schedulerEvents: [
{
create: 'CREATE EVENT obj1 ON SCHEDULE EVERY 1 HOUR DO BEGIN END',
drop: 'DROP EVENT obj1',
objectTypeField: 'schedulerEvents',
expected: {
pureName: 'obj1',
status: 'ENABLED',
eventType: 'RECURRING',
intervalValue: '1',
intervalField: 'HOUR',
},
{
type: 'functions',
create1:
'CREATE FUNCTION obj1() returns int LANGUAGE plpgsql AS $$ declare res integer; begin select count(*) into res from t1; return res; end; $$',
create2:
'CREATE FUNCTION obj2() returns int LANGUAGE plpgsql AS $$ declare res integer; begin select count(*) into res from t2; return res; end; $$',
drop1: 'DROP FUNCTION obj1',
drop2: 'DROP FUNCTION obj2',
},
{
create: 'CREATE EVENT obj1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 DAY DO BEGIN END',
drop: 'DROP EVENT obj1',
objectTypeField: 'schedulerEvents',
expected: {
pureName: 'obj1',
status: 'ENABLED',
eventType: 'ONE TIME',
},
],
supportSchemas: true,
supportRenameSqlObject: true,
defaultSchemaName: 'public',
dumpFile: 'data/chinook-postgre.sql',
dumpChecks: [
{
sql: 'select count(*) as res from "public"."Genre"',
res: '25',
},
],
};
const mariaDbEngine = {
label: 'MariaDB',
connection: {
engine: 'mariadb@dbgate-plugin-mysql',
password: 'Pwd2020Db',
user: 'root',
server: 'localhost',
port: 15004,
},
objects: [views],
dbSnapshotBySeconds: true,
dumpFile: 'data/chinook-mysql.sql',
dumpChecks: [
{
sql: 'select count(*) as res from genre',
res: '25',
},
],
};
const postgreSqlEngine = {
label: 'PostgreSQL',
connection: {
engine: 'postgres@dbgate-plugin-postgres',
password: 'Pwd2020Db',
user: 'postgres',
server: 'localhost',
port: 15000,
},
objects: [
views,
matviews,
{
type: 'procedures',
create1: 'CREATE PROCEDURE obj1() LANGUAGE SQL AS $$ select * from t1 $$',
create2: 'CREATE PROCEDURE obj2() LANGUAGE SQL AS $$ select * from t2 $$',
drop1: 'DROP PROCEDURE obj1',
drop2: 'DROP PROCEDURE obj2',
},
{
type: 'functions',
create1:
'CREATE FUNCTION obj1() returns int LANGUAGE plpgsql AS $$ declare res integer; begin select count(*) into res from t1; return res; end; $$',
create2:
'CREATE FUNCTION obj2() returns int LANGUAGE plpgsql AS $$ declare res integer; begin select count(*) into res from t2; return res; end; $$',
drop1: 'DROP FUNCTION obj1',
drop2: 'DROP FUNCTION obj2',
},
],
supportSchemas: true,
supportRenameSqlObject: true,
defaultSchemaName: 'public',
dumpFile: 'data/chinook-postgre.sql',
dumpChecks: [
{
sql: 'select count(*) as res from "public"."Genre"',
res: '25',
},
],
parametersOtherSql: ['CREATE PROCEDURE obj2(a integer, b integer) LANGUAGE SQL AS $$ select * from t1 $$'],
parameters: [
{
testName: 'simple',
create: 'CREATE PROCEDURE obj1(a integer) LANGUAGE SQL AS $$ select * from t1 $$',
drop: 'DROP PROCEDURE obj1',
objectTypeField: 'procedures',
list: [
{
parameterName: 'a',
parameterMode: 'IN',
dataType: 'integer',
},
],
},
{
testName: 'dataTypes',
create: 'CREATE PROCEDURE obj1(a integer, b varchar(20), c numeric(18,2)) LANGUAGE SQL AS $$ select * from t1 $$',
drop: 'DROP PROCEDURE obj1',
objectTypeField: 'procedures',
list: [
{
parameterName: 'a',
parameterMode: 'IN',
dataType: 'integer',
},
{
parameterName: 'b',
parameterMode: 'IN',
dataType: 'varchar',
},
{
parameterName: 'c',
parameterMode: 'IN',
dataType: 'numeric',
},
],
},
{
testName: 'paramModes',
create: 'CREATE PROCEDURE obj1(IN a integer, INOUT b integer) LANGUAGE SQL AS $$ select * from t1 $$',
drop: 'DROP PROCEDURE obj1',
objectTypeField: 'procedures',
list: [
{
parameterName: 'a',
parameterMode: 'IN',
dataType: 'integer',
},
{
parameterName: 'b',
parameterMode: 'INOUT',
dataType: 'integer',
},
],
},
{
testName: 'paramModesFunction',
objectTypeField: 'functions',
create: `
create or replace function obj1(
out min_len int,
out max_len int)
language plpgsql
as $$
begin
select min(id),
max(id)
into min_len, max_len
from t1;
end;$$`,
drop: 'DROP FUNCTION obj1',
list: [
{
parameterName: 'min_len',
parameterMode: 'OUT',
dataType: 'integer',
},
{
parameterName: 'max_len',
parameterMode: 'OUT',
dataType: 'integer',
},
],
},
],
triggers: [
{
testName: 'triggers after each row',
create: `CREATE TRIGGER obj1
AFTER INSERT ON t1
FOR EACH ROW
EXECUTE FUNCTION test_function();
`,
drop: 'DROP TRIGGER obj1 ON t1;',
triggerOtherCreateSql: `CREATE OR REPLACE FUNCTION test_function()
RETURNS TRIGGER AS $$
BEGIN
END;
$$ LANGUAGE plpgsql;`,
triggerOtherDropSql: 'DROP FUNCTION test_function',
objectTypeField: 'triggers',
expected: {
pureName: 'obj1',
eventType: 'INSERT',
triggerTiming: 'AFTER',
},
],
},
{
label: 'SQL Server',
connection: {
engine: 'mssql@dbgate-plugin-mssql',
password: 'Pwd2020Db',
user: 'sa',
server: 'mssql',
port: 1433,
},
local: {
server: 'localhost',
port: 15002,
},
objects: [
views,
{
type: 'procedures',
create1: 'CREATE PROCEDURE obj1 AS SELECT id FROM t1',
create2: 'CREATE PROCEDURE obj2 AS SELECT id FROM t2',
drop1: 'DROP PROCEDURE obj1',
drop2: 'DROP PROCEDURE obj2',
{
testName: 'triggers before each row',
create: `CREATE TRIGGER obj1
BEFORE INSERT ON t1
FOR EACH ROW
EXECUTE FUNCTION test_function();
`,
drop: 'DROP TRIGGER obj1 ON t1;',
triggerOtherCreateSql: `CREATE OR REPLACE FUNCTION test_function()
RETURNS TRIGGER AS $$
BEGIN
END;
$$ LANGUAGE plpgsql;`,
triggerOtherDropSql: 'DROP FUNCTION test_function',
objectTypeField: 'triggers',
expected: {
pureName: 'obj1',
eventType: 'INSERT',
triggerTiming: 'BEFORE',
},
],
supportSchemas: true,
supportRenameSqlObject: true,
defaultSchemaName: 'dbo',
// skipSeparateSchemas: true,
},
],
};
const sqlServerEngine = {
label: 'SQL Server',
connection: {
engine: 'mssql@dbgate-plugin-mssql',
password: 'Pwd2020Db',
user: 'sa',
server: 'localhost',
port: 15002,
},
{
label: 'SQLite',
generateDbFile: true,
connection: {
engine: 'sqlite@dbgate-plugin-sqlite',
objects: [
views,
{
type: 'procedures',
create1: 'CREATE PROCEDURE obj1 AS SELECT id FROM t1',
create2: 'CREATE PROCEDURE obj2 AS SELECT id FROM t2',
drop1: 'DROP PROCEDURE obj1',
drop2: 'DROP PROCEDURE obj2',
},
objects: [views],
skipOnCI: false,
{
type: 'triggers',
create1: 'CREATE TRIGGER obj1 ON t1 AFTER INSERT AS BEGIN SELECT * FROM t1 END',
create2: 'CREATE TRIGGER obj2 ON t2 AFTER INSERT AS BEGIN SELECT * FROM t2 END',
drop1: 'DROP TRIGGER obj1',
drop2: 'DROP TRIGGER obj2',
},
],
parametersOtherSql: ['CREATE PROCEDURE obj2 (@p1 int, @p2 int) AS SELECT id from t1'],
parameters: [
{
testName: 'simple',
create: 'CREATE PROCEDURE obj1 (@param1 int) AS SELECT id from t1',
drop: 'DROP PROCEDURE obj1',
objectTypeField: 'procedures',
list: [
{
parameterName: '@param1',
parameterMode: 'IN',
dataType: 'int',
},
],
},
{
testName: 'dataTypes',
create: 'CREATE PROCEDURE obj1 (@p1 bit, @p2 nvarchar(20), @p3 decimal(18,2), @p4 float) AS SELECT id from t1',
drop: 'DROP PROCEDURE obj1',
objectTypeField: 'procedures',
list: [
{
parameterName: '@p1',
parameterMode: 'IN',
dataType: 'bit',
},
{
parameterName: '@p2',
parameterMode: 'IN',
dataType: 'nvarchar(20)',
},
{
parameterName: '@p3',
parameterMode: 'IN',
dataType: 'decimal(18,2)',
},
{
parameterName: '@p4',
parameterMode: 'IN',
dataType: 'float',
},
],
},
{
testName: 'outputParam',
create: 'CREATE PROCEDURE obj1 (@p1 int OUTPUT) AS SELECT id from t1',
drop: 'DROP PROCEDURE obj1',
objectTypeField: 'procedures',
list: [
{
parameterName: '@p1',
parameterMode: 'OUT',
dataType: 'int',
},
],
},
],
supportSchemas: true,
supportRenameSqlObject: true,
defaultSchemaName: 'dbo',
// skipSeparateSchemas: true,
triggers: [
{
testName: 'triggers before each row',
create: `CREATE TRIGGER obj1 ON t1 AFTER INSERT AS BEGIN SELECT * FROM t1 END`,
drop: 'DROP TRIGGER obj1',
objectTypeField: 'triggers',
expected: {
pureName: 'obj1',
eventType: 'INSERT',
triggerTiming: 'AFTER',
},
},
{
testName: 'triggers before each row',
create: `CREATE TRIGGER obj1 ON t1 AFTER UPDATE AS BEGIN SELECT * FROM t1 END`,
drop: 'DROP TRIGGER obj1',
objectTypeField: 'triggers',
expected: {
pureName: 'obj1',
eventType: 'UPDATE',
triggerTiming: 'AFTER',
},
},
],
};
const sqliteEngine = {
label: 'SQLite',
generateDbFile: true,
connection: {
engine: 'sqlite@dbgate-plugin-sqlite',
},
{
label: 'CockroachDB',
connection: {
engine: 'cockroach@dbgate-plugin-postgres',
user: 'root',
server: 'cockroachdb',
port: 26257,
objects: [views],
skipOnCI: false,
skipChangeColumn: true,
triggers: [
{
testName: 'triggers after each row insert',
create: `CREATE TRIGGER obj1 AFTER INSERT ON t1 FOR EACH ROW BEGIN SELECT * FROM t1; END;`,
drop: `DROP TRIGGER obj1;`,
objectTypeField: 'triggers',
expected: {
pureName: 'obj1',
eventType: 'INSERT',
triggerTiming: 'AFTER',
},
},
local: {
server: 'localhost',
port: 15003,
{
testName: 'triggers before each row update',
create: `CREATE TRIGGER obj1 BEFORE UPDATE ON t1 FOR EACH ROW BEGIN SELECT * FROM t1; END;`,
drop: `DROP TRIGGER obj1;`,
objectTypeField: 'triggers',
expected: {
pureName: 'obj1',
eventType: 'UPDATE',
triggerTiming: 'BEFORE',
},
},
skipOnCI: true,
objects: [views, matviews],
],
};
const cockroachDbEngine = {
label: 'CockroachDB',
connection: {
engine: 'cockroach@dbgate-plugin-postgres',
user: 'root',
server: 'localhost',
port: 15003,
},
{
label: 'ClickHouse',
connection: {
engine: 'clickhouse@dbgate-plugin-clickhouse',
databaseUrl: 'http://clickhouse:8123',
password: 'Pwd2020Db',
},
local: {
databaseUrl: 'http://localhost:15005',
},
skipOnCI: false,
objects: [views],
skipDataModifications: true,
skipReferences: true,
skipIndexes: true,
skipNullability: true,
skipUnique: true,
skipAutoIncrement: true,
skipPkColumnTesting: true,
skipDataDuplicator: true,
skipStringLength: true,
alterTableAddColumnSyntax: true,
dbSnapshotBySeconds: true,
objects: [views, matviews],
};
const clickhouseEngine = {
label: 'ClickHouse',
connection: {
engine: 'clickhouse@dbgate-plugin-clickhouse',
databaseUrl: 'http://localhost:15005',
password: 'Pwd2020Db',
},
objects: [views],
skipDataModifications: true,
skipReferences: true,
skipIndexes: true,
skipNullability: true,
skipUnique: true,
skipAutoIncrement: true,
skipPkColumnTesting: true,
skipDataDuplicator: true,
skipStringLength: true,
alterTableAddColumnSyntax: true,
dbSnapshotBySeconds: true,
skipChangeColumn: true,
};
const oracleEngine = {
label: 'Oracle',
connection: {
engine: 'oracle@dbgate-plugin-oracle',
password: 'Pwd2020Db',
user: 'system',
server: 'localhost',
port: 15006,
serviceName: 'xe',
},
skipOnCI: false,
dbSnapshotBySeconds: true,
setNullDefaultInsteadOfDrop: true,
skipIncrementalAnalysis: true,
objects: [
views,
{
type: 'procedures',
create1: 'CREATE PROCEDURE ~obj1 AS BEGIN SELECT ~id FROM ~t1 END',
create2: 'CREATE PROCEDURE ~obj2 AS BEGIN SELECT ~id FROM ~t2 END',
drop1: 'DROP PROCEDURE ~obj1',
drop2: 'DROP PROCEDURE ~obj2',
},
{
type: 'functions',
create1:
'CREATE FUNCTION ~obj1 RETURN NUMBER IS v_count NUMBER; \n BEGIN SELECT COUNT(*) INTO v_count FROM ~t1;\n RETURN v_count;\n END ~obj1',
create2:
'CREATE FUNCTION ~obj2 RETURN NUMBER IS v_count NUMBER; \n BEGIN SELECT COUNT(*) INTO v_count FROM ~t2;\n RETURN v_count;\n END ~obj2',
drop1: 'DROP FUNCTION ~obj1',
drop2: 'DROP FUNCTION ~obj2',
},
],
triggers: [
{
testName: 'triggers after each row',
create: 'CREATE OR REPLACE TRIGGER obj1 AFTER INSERT ON "t1" FOR EACH ROW BEGIN END obj1;',
drop: 'DROP TRIGGER obj1;',
objectTypeField: 'triggers',
expected: {
pureName: 'OBJ1',
eventType: 'INSERT',
triggerTiming: 'AFTER EACH ROW',
},
},
{
testName: 'triggers before each row',
create: 'CREATE OR REPLACE TRIGGER obj1 BEFORE INSERT ON "t1" FOR EACH ROW BEGIN END obj1;',
drop: 'DROP TRIGGER obj1;',
objectTypeField: 'triggers',
expected: {
pureName: 'OBJ1',
eventType: 'INSERT',
triggerTiming: 'BEFORE EACH ROW',
},
},
],
};
const enginesOnCi = [
// all engines, which would be run on GitHub actions
mysqlEngine,
// mariaDbEngine,
postgreSqlEngine,
sqlServerEngine,
sqliteEngine,
// cockroachDbEngine,
clickhouseEngine,
oracleEngine,
];
const filterLocal = [
// filter local testing
'-MySQL',
'-MariaDB',
'PostgreSQL',
'-SQL Server',
'-SQLite',
'-CockroachDB',
'-ClickHouse',
const enginesOnLocal = [
// all engines, which would be run on local test
mysqlEngine,
// mariaDbEngine,
// postgreSqlEngine,
// sqlServerEngine,
sqliteEngine,
// cockroachDbEngine,
// clickhouseEngine,
// oracleEngine,
];
const enginesPostgre = engines.filter(x => x.label == 'PostgreSQL');
module.exports = process.env.CITEST ? enginesOnCi : enginesOnLocal;
module.exports = process.env.CITEST
? engines.filter(x => !x.skipOnCI)
: engines.filter(x => filterLocal.find(y => x.label == y));
module.exports.enginesPostgre = enginesPostgre;
module.exports.mysqlEngine = mysqlEngine;
module.exports.mariaDbEngine = mariaDbEngine;
module.exports.postgreSqlEngine = postgreSqlEngine;
module.exports.sqlServerEngine = sqlServerEngine;
module.exports.sqliteEngine = sqliteEngine;
module.exports.cockroachDbEngine = cockroachDbEngine;
module.exports.clickhouseEngine = clickhouseEngine;
module.exports.oracleEngine = oracleEngine;

View File

@@ -1,6 +1,6 @@
{
"name": "dbgate-integration-tests",
"version": "5.0.0-alpha.1",
"version": "6.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",
@@ -11,14 +11,11 @@
"scripts": {
"wait:local": "cross-env DEVMODE=1 LOCALTEST=1 node wait.js",
"wait:ci": "cross-env DEVMODE=1 CITEST=1 node wait.js",
"test:local": "cross-env DEVMODE=1 LOCALTEST=1 jest",
"test:local": "cross-env DEVMODE=1 LOCALTEST=1 jest --testTimeout=5000",
"test:local:path": "cross-env DEVMODE=1 LOCALTEST=1 jest --runTestsByPath __tests__/data-duplicator.spec.js",
"test:ci": "cross-env DEVMODE=1 CITEST=1 jest --runInBand --json --outputFile=result.json --testLocationInResults --detectOpenHandles --forceExit",
"test:ci": "cross-env DEVMODE=1 CITEST=1 jest --runInBand --json --outputFile=result.json --testLocationInResults --detectOpenHandles --forceExit --testTimeout=10000",
"run:local": "docker-compose down && docker-compose up -d && yarn wait:local && yarn test:local"
},
"jest": {
"testTimeout": 5000
},
"devDependencies": {
"cross-env": "^7.0.3",
"jest": "^27.0.1",

View File

@@ -1,27 +1,16 @@
const requireEngineDriver = require('dbgate-api/src/utility/requireEngineDriver');
const crypto = require('crypto');
function randomDbName() {
function randomDbName(dialect) {
const generatedKey = crypto.randomBytes(6);
const newKey = generatedKey.toString('hex');
return `db${newKey}`;
}
function extractConnection(engine) {
const { connection } = engine;
if (process.env.LOCALTEST && engine.local) {
return {
...connection,
...engine.local,
};
}
return connection;
const res = `db${newKey}`;
if (dialect.upperCaseAllDbObjectNames) return res.toUpperCase();
return res;
}
async function connect(engine, database) {
const connection = extractConnection(engine);
const { connection } = engine;
const driver = requireEngineDriver(connection);
if (engine.generateDbFile) {
@@ -32,19 +21,21 @@ async function connect(engine, database) {
return conn;
} else {
const conn = await driver.connect(connection);
await driver.query(conn, `CREATE DATABASE ${database}`);
const dmp = driver.createDumper();
dmp.createDatabase(database);
await driver.query(conn, dmp.s);
await driver.close(conn);
const res = await driver.connect({
...connection,
database,
database: (driver.dialect.userDatabaseNamePrefix ?? '') + database,
});
return res;
}
}
async function prepareConnection(engine, database) {
const connection = extractConnection(engine);
const { connection } = engine;
const driver = requireEngineDriver(connection);
if (engine.generateDbFile) {
@@ -55,12 +46,14 @@ async function prepareConnection(engine, database) {
};
} else {
const conn = await driver.connect(connection);
await driver.query(conn, `CREATE DATABASE ${database}`);
const dmp = driver.createDumper();
dmp.createDatabase(database);
await driver.query(conn, dmp.s);
await driver.close(conn);
return {
...connection,
database,
database: (driver.dialect.userDatabaseNamePrefix ?? '') + database,
isPreparedOnly: true,
};
}
@@ -71,7 +64,7 @@ const testWrapper =
async (label, ...other) => {
const engine = other[other.length - 1];
const driver = requireEngineDriver(engine.connection);
const conn = await connect(engine, randomDbName());
const conn = await connect(engine, randomDbName(driver.dialect));
try {
await body(conn, driver, ...other);
} finally {
@@ -84,14 +77,13 @@ const testWrapperPrepareOnly =
async (label, ...other) => {
const engine = other[other.length - 1];
const driver = requireEngineDriver(engine.connection);
const conn = await prepareConnection(engine, randomDbName());
const conn = await prepareConnection(engine, randomDbName(driver.dialect));
await body(conn, driver, ...other);
};
module.exports = {
randomDbName,
connect,
extractConnection,
testWrapper,
testWrapperPrepareOnly,
};

View File

@@ -1,13 +1,12 @@
const requireEngineDriver = require('dbgate-api/src/utility/requireEngineDriver');
const engines = require('./engines');
const { extractConnection } = require('./tools');
global.DBGATE_PACKAGES = {
'dbgate-tools': require('dbgate-tools'),
'dbgate-sqltree': require('dbgate-sqltree'),
};
async function connectEngine(engine) {
const connection = extractConnection(engine);
const { connection } = engine;
const driver = requireEngineDriver(connection);
for (;;) {
try {

View File

@@ -1,6 +1,6 @@
{
"private": true,
"version": "5.5.7-beta.58",
"version": "6.1.6",
"name": "dbgate-all",
"workspaces": [
"packages/*",
@@ -35,6 +35,7 @@
"build:lib": "yarn build:sqltree && yarn build:tools && yarn build:filterparser && yarn build:datalib",
"build:app": "yarn plugins:copydist && cd app && yarn install && yarn build",
"build:api": "yarn workspace dbgate-api build",
"build:api:doc": "yarn workspace dbgate-api build:doc",
"build:web": "yarn workspace dbgate-web build",
"build:plugins:frontend": "workspaces-run --only=\"dbgate-plugin-*\" -- yarn build:frontend",
"build:plugins:backend": "workspaces-run --only=\"dbgate-plugin-*\" -- yarn build:backend",
@@ -46,13 +47,13 @@
"setCurrentVersion": "node setCurrentVersion",
"printSecrets": "node printSecrets",
"generatePadFile": "node generatePadFile",
"adjustPackageJson": "node adjustPackageJson",
"fillPackagedPlugins": "node fillPackagedPlugins",
"resetPackagedPlugins": "node resetPackagedPlugins",
"prettier": "prettier --write packages/api/src && prettier --write packages/datalib/src && prettier --write packages/filterparser/src && prettier --write packages/sqltree/src && prettier --write packages/tools/src && prettier --write packages/types && prettier --write packages/web/src && prettier --write app/src",
"copy:docker:build": "copyfiles packages/api/dist/* docker -f && copyfiles packages/web/public/* docker -u 2 && copyfiles \"packages/web/public/**/*\" docker -u 2 && copyfiles \"plugins/dist/**/*\" docker/plugins -u 2",
"copy:packer:build": "copyfiles packages/api/dist/* packer/build -f && copyfiles packages/web/public/* packer/build -u 2 && copyfiles \"packages/web/public/**/*\" packer/build -u 2 && copyfiles \"plugins/dist/**/*\" packer/build/plugins -u 2 && copyfiles packer/install-packages.sh packer/build -f",
"install:drivers:docker": "cd docker && yarn init --yes && yarn add better-sqlite3 && yarn add oracledb && cd ..",
"copy:packer:build": "copyfiles packages/api/dist/* packer/build -f && copyfiles packages/web/public/* packer/build -u 2 && copyfiles \"packages/web/public/**/*\" packer/build -u 2 && copyfiles \"plugins/dist/**/*\" packer/build/plugins -u 2 && copyfiles packer/install-packages.sh packer/build -f && yarn install:drivers:packer",
"install:drivers:docker": "node common/defineVolatileDependencies.js docker && cd docker && yarn install && cd ..",
"install:drivers:packer": "node common/defineVolatileDependencies.js packer/build",
"prepare:docker": "yarn plugins:copydist && yarn build:web && yarn build:api && yarn copy:docker:build && yarn install:drivers:docker",
"prepare:packer": "yarn plugins:copydist && yarn build:web && yarn build:api && yarn copy:packer:build",
"start": "concurrently --kill-others-on-fail \"yarn start:api\" \"yarn start:web\"",
@@ -61,7 +62,8 @@
"ts:web": "yarn workspace dbgate-web ts",
"ts": "yarn ts:api && yarn ts:web",
"postinstall": "yarn resetPackagedPlugins && yarn build:lib && patch-package && yarn build:plugins:frontend",
"dbgate-serve": "node packages/dbgate/bin/dbgate-serve.js"
"dbgate-serve": "node packages/dbgate/bin/dbgate-serve.js",
"workflows": "node common/processWorkflows.js"
},
"dependencies": {
"concurrently": "^5.1.0",

View File

@@ -1,60 +1,47 @@
DEVMODE=1
CONNECTIONS=mysql,postgres,postgres1,mongo,mongo2,mysqlssh,sqlite,relational
CONNECTIONS=mysql,postgres,mongo,redis,mssql,oracle
LABEL_mysql=MySql localhost
SERVER_mysql=localhost
LABEL_mysql=MySql
SERVER_mysql=dbgatedckstage1.sprinx.cz
USER_mysql=root
PASSWORD_mysql=test
PORT_mysql=3307
PASSWORD_mysql=Pwd2020Db
PORT_mysql=3306
ENGINE_mysql=mysql@dbgate-plugin-mysql
LABEL_postgres=Postgres localhost
SERVER_postgres=localhost
LABEL_postgres=Postgres
SERVER_postgres=dbgatedckstage1.sprinx.cz
USER_postgres=postgres
PASSWORD_postgres=Pwd2020Db
PORT_postgres=5432
ENGINE_postgres=postgres@dbgate-plugin-postgres
LABEL_postgres1=Postgres localhost test DB
SERVER_postgres1=localhost
USER_postgres1=postgres
PASSWORD_postgres1=Pwd2020Db
PORT_postgres1=5432
ENGINE_postgres1=postgres@dbgate-plugin-postgres
DATABASE_postgres1=test
LABEL_mongo=Mongo URL
URL_mongo=mongodb://localhost:27017
LABEL_mongo=Mongo
SERVER_mongo=dbgatedckstage1.sprinx.cz
USER_mongo=root
PASSWORD_mongo=Pwd2020Db
PORT_mongo=27017
ENGINE_mongo=mongo@dbgate-plugin-mongo
LABEL_mongo2=Mongo Server
SERVER_mongo2=localhost
ENGINE_mongo2=mongo@dbgate-plugin-mongo
LABEL_redis=Redis
SERVER_redis=dbgatedckstage1.sprinx.cz
ENGINE_redis=redis@dbgate-plugin-redis
PORT_redis=6379
LABEL_mysqlssh=MySql SSH
SERVER_mysqlssh=localhost
USER_mysqlssh=root
PASSWORD_mysqlssh=xxx
PORT_mysqlssh=3316
ENGINE_mysqlssh=mysql@dbgate-plugin-mysql
USE_SSH_mysqlssh=1
SSH_HOST_mysqlssh=demo.dbgate.org
SSH_PORT_mysqlssh=22
SSH_MODE_mysqlssh=userPassword
SSH_LOGIN_mysqlssh=root
SSH_PASSWORD_mysqlssh=xxx
LABEL_mssql=SQL Server
SERVER_mssql=dbgatedckstage1.sprinx.cz
USER_mssql=sa
PASSWORD_mssql=Pwd2020Db
PORT_mssql=1433
ENGINE_mssql=mssql@dbgate-plugin-mssql
LABEL_sqlite=sqlite
FILE_sqlite=/home/jena/.dbgate/files/sqlite/feeds.sqlite
ENGINE_sqlite=sqlite@dbgate-plugin-sqlite
LABEL_relational=Relational dataset repo
SERVER_relational=relational.fit.cvut.cz
USER_relational=guest
PASSWORD_relational=relational
ENGINE_relational=mariadb@dbgate-plugin-mysql
READONLY_relational=1
LABEL_oracle=Oracle
SERVER_oracle=dbgatedckstage1.sprinx.cz
USER_oracle=system
PASSWORD_oracle=Pwd2020Db
PORT_oracle=1521
ENGINE_oracle=oracle@dbgate-plugin-oracle
SERVICE_NAME_oracle=xe
# SETTINGS_dataGrid.showHintColumns=1

View File

@@ -12,6 +12,6 @@ DBCONFIG_mysql=[{"name":"Chinook","connectionColor":"cyan"}]
SINGLE_CONNECTION=mysql
SINGLE_DATABASE=Chinook
# SINGLE_DATABASE=Chinook
PERMISSIONS=files/charts/read

View File

@@ -1,7 +1,7 @@
{
"name": "dbgate-api",
"main": "src/index.js",
"version": "5.0.0-alpha.1",
"version": "6.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",
@@ -19,11 +19,6 @@
"files": [
"src"
],
"build": {
"files": [
"!node_modules/cpu-features/build/**"
]
},
"dependencies": {
"@aws-sdk/rds-signer": "^3.665.0",
"activedirectory2": "^2.1.0",
@@ -34,10 +29,10 @@
"compare-versions": "^3.6.0",
"cors": "^2.8.5",
"cross-env": "^6.0.3",
"dbgate-datalib": "^5.0.0-alpha.1",
"dbgate-query-splitter": "^4.11.2",
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-tools": "^5.0.0-alpha.1",
"dbgate-datalib": "^6.0.0-alpha.1",
"dbgate-query-splitter": "^4.11.3",
"dbgate-sqltree": "^6.0.0-alpha.1",
"dbgate-tools": "^6.0.0-alpha.1",
"debug": "^4.3.4",
"diff": "^5.0.0",
"diff2html": "^3.4.13",
@@ -65,7 +60,7 @@
"rimraf": "^3.0.0",
"semver": "^7.6.3",
"simple-encryptor": "^4.0.0",
"ssh2": "^1.11.0",
"ssh2": "^1.16.0",
"stream-json": "^1.8.0",
"tar": "^6.0.5"
},
@@ -86,7 +81,7 @@
"devDependencies": {
"@types/fs-extra": "^9.0.11",
"@types/lodash": "^4.14.149",
"dbgate-types": "^5.0.0-alpha.1",
"dbgate-types": "^6.0.0-alpha.1",
"env-cmd": "^10.1.0",
"jsdoc-to-markdown": "^9.0.5",
"node-loader": "^1.0.2",

View File

@@ -218,7 +218,7 @@ class LoginsProvider extends AuthProviderBase {
};
}
if (password == process.env[`LOGIN_PASSWORD_${login}`]) {
if (password && password == process.env[`LOGIN_PASSWORD_${login}`]) {
return {
accessToken: jwt.sign(
{
@@ -230,7 +230,7 @@ class LoginsProvider extends AuthProviderBase {
),
};
}
return { error: 'Invalid credentials' };
}
@@ -271,11 +271,10 @@ function hasEnvLogins() {
return false;
}
function detectEnvAuthProvider() {
function detectEnvAuthProviderCore() {
if (process.env.AUTH_PROVIDER) {
return process.env.AUTH_PROVIDER;
}
if (process.env.STORAGE_DATABASE) {
return 'denyall';
}
@@ -291,6 +290,14 @@ function detectEnvAuthProvider() {
return 'none';
}
function detectEnvAuthProvider() {
const authProvider = detectEnvAuthProviderCore();
if (process.env.BASIC_AUTH && authProvider != 'logins' && authProvider != 'ad') {
throw new Error(`BASIC_AUTH is not supported with ${authProvider} auth provider`);
}
return authProvider;
}
function createEnvAuthProvider() {
const authProvider = detectEnvAuthProvider();
switch (authProvider) {

View File

@@ -9,6 +9,7 @@ const _ = require('lodash');
const AsyncLock = require('async-lock');
const jwt = require('jsonwebtoken');
const processArgs = require('../utility/processArgs');
const currentVersion = require('../currentVersion');
const platformInfo = require('../utility/platformInfo');
const connections = require('../controllers/connections');
@@ -62,6 +63,8 @@ module.exports = {
const logoutUrl = storageConnectionError ? null : await authProvider.getLogoutUrl();
const adminConfig = storageConnectionError ? null : await storage.readConfig({ group: 'admin' });
storage.startRefreshLicense();
const isAdminPasswordMissing = !!(
process.env.STORAGE_DATABASE &&
!process.env.ADMIN_PASSWORD &&
@@ -81,7 +84,8 @@ module.exports = {
isElectron: platformInfo.isElectron,
isLicenseValid,
isLicenseExpired: checkedLicense?.isExpired,
trialDaysLeft: checkedLicense?.isGeneratedTrial && !checkedLicense?.isExpired ? checkedLicense?.daysLeft : null,
trialDaysLeft:
checkedLicense?.licenseTypeObj?.isTrial && !checkedLicense?.isExpired ? checkedLicense?.daysLeft : null,
checkedLicense,
configurationError,
logoutUrl,
@@ -99,7 +103,10 @@ module.exports = {
adminPasswordState: adminConfig?.adminPasswordState,
storageDatabase: process.env.STORAGE_DATABASE,
logsFilePath: getLogsFilePath(),
connectionsFilePath: path.join(datadir(), 'connections.jsonl'),
connectionsFilePath: path.join(
datadir(),
processArgs.runE2eTests ? 'connections-e2etests.jsonl' : 'connections.jsonl'
),
...currentVersion,
};

View File

@@ -199,8 +199,11 @@ module.exports = {
const dir = datadir();
if (!portalConnections) {
// @ts-ignore
this.datastore = new JsonLinesDatabase(path.join(dir, 'connections.jsonl'));
this.datastore = new JsonLinesDatabase(
path.join(dir, processArgs.runE2eTests ? 'connections-e2etests.jsonl' : 'connections.jsonl')
);
}
await this.checkUnsavedConnectionsLimit();
},
list_meta: true,
@@ -219,7 +222,7 @@ module.exports = {
},
test_meta: true,
test(connection) {
test({ connection, requestDbList = false }) {
const subprocess = fork(
global['API_PACKAGE'] || process.argv[1],
[
@@ -234,7 +237,7 @@ module.exports = {
}
);
pipeForkLogs(subprocess);
subprocess.send(connection);
subprocess.send({ ...connection, requestDbList });
return new Promise(resolve => {
subprocess.on('message', resp => {
if (handleProcessCommunication(resp, subprocess)) return;
@@ -264,7 +267,7 @@ module.exports = {
}
if (test) {
const testRes = await this.test(res);
const testRes = await this.test({ connection: res });
if (testRes.msgtype == 'connected') {
volatileConnections[res._id] = res;
return {
@@ -300,6 +303,32 @@ module.exports = {
return res;
},
async checkUnsavedConnectionsLimit() {
if (!this.datastore) {
return;
}
const MAX_UNSAVED_CONNECTIONS = 5;
await this.datastore.transformAll(connections => {
const count = connections.filter(x => x.unsaved).length;
if (count > MAX_UNSAVED_CONNECTIONS) {
const res = [];
let unsavedToSkip = count - MAX_UNSAVED_CONNECTIONS;
for (const item of connections) {
if (item.unsaved) {
if (unsavedToSkip > 0) {
unsavedToSkip--;
} else {
res.push(item);
}
} else {
res.push(item);
}
}
return res;
}
});
},
update_meta: true,
async update({ _id, values }, req) {
if (portalConnections) return;
@@ -483,4 +512,10 @@ module.exports = {
}
return null;
},
reloadConnectionList_meta: true,
async reloadConnectionList() {
if (portalConnections) return;
await this.datastore.unload();
},
};

View File

@@ -229,9 +229,9 @@ module.exports = {
},
loadKeys_meta: true,
async loadKeys({ conid, database, root, filter }, req) {
async loadKeys({ conid, database, root, filter, limit }, req) {
testConnectionPermission(conid, req);
return this.loadDataCore('loadKeys', { conid, database, root, filter });
return this.loadDataCore('loadKeys', { conid, database, root, filter, limit });
},
exportKeys_meta: true,

View File

@@ -49,7 +49,8 @@ logger.info('Finished job script');
dbgateApi.runScript(run);
`;
const loaderScriptTemplate = (functionName, props, runid) => `
const loaderScriptTemplate = (prefix, functionName, props, runid) => `
${prefix}
const dbgateApi = require(process.env.DBGATE_API);
dbgateApi.initializeApiEnvironment();
${requirePluginsTemplate(extractShellApiPlugins(functionName, props))}
@@ -111,7 +112,7 @@ module.exports = {
const scriptFile = path.join(uploadsdir(), runid + '.js');
fs.writeFileSync(`${scriptFile}`, scriptText);
fs.mkdirSync(directory);
const pluginNames = _.union(fs.readdirSync(pluginsdir()), packagedPluginList);
const pluginNames = extractPlugins(scriptText);
logger.info({ scriptFile }, 'Running script');
// const subprocess = fork(scriptFile, ['--checkParent', '--max-old-space-size=8192'], {
const subprocess = fork(
@@ -149,7 +150,7 @@ module.exports = {
byline(subprocess.stdout).on('data', pipeDispatcher('info'));
byline(subprocess.stderr).on('data', pipeDispatcher('error'));
subprocess.on('exit', code => {
this.rejectRequest(runid, { message: 'No data retured, maybe input data source is too big' });
this.rejectRequest(runid, { message: 'No data returned, maybe input data source is too big' });
logger.info({ code, pid: subprocess.pid }, 'Exited process');
socket.emit(`runner-done-${runid}`, code);
});
@@ -224,10 +225,14 @@ module.exports = {
loadReader_meta: true,
async loadReader({ functionName, props }) {
const prefix = extractShellApiPlugins(functionName)
.map(packageName => `// @require ${packageName}\n`)
.join('');
const promise = new Promise((resolve, reject) => {
const runid = crypto.randomUUID();
this.requests[runid] = [resolve, reject];
this.startCore(runid, loaderScriptTemplate(functionName, props, runid));
this.startCore(runid, loaderScriptTemplate(prefix, functionName, props, runid));
});
return promise;
},

View File

@@ -52,7 +52,7 @@ module.exports = {
if (existing) return existing;
const connection = await connections.getCore({ conid });
if (!connection) {
throw new Error(`Connection with conid="${conid}" not fund`);
throw new Error(`Connection with conid="${conid}" not found`);
}
if (connection.passwordMode == 'askPassword' || connection.passwordMode == 'askUser') {
throw new MissingCredentialsError({ conid, passwordMode: connection.passwordMode });

View File

@@ -26,4 +26,6 @@ module.exports = {
async readConfig({ group }) {
return {};
},
startRefreshLicense() {},
};

View File

@@ -1,5 +1,5 @@
module.exports = {
version: '5.0.0-alpha.1',
buildTime: '2021-04-17T07:22:49.702Z'
version: '6.0.0-alpha.1',
buildTime: '2024-12-01T00:00:00Z'
};

View File

@@ -28,6 +28,7 @@ const files = require('./controllers/files');
const scheduler = require('./controllers/scheduler');
const queryHistory = require('./controllers/queryHistory');
const onFinished = require('on-finished');
const processArgs = require('./utility/processArgs');
const { rundir } = require('./utility/directories');
const platformInfo = require('./utility/platformInfo');
@@ -77,6 +78,8 @@ function start() {
app.use(getExpressPath('/'), express.static('/home/dbgate-docker/public'));
} else if (platformInfo.isAwsUbuntuLayout) {
app.use(getExpressPath('/'), express.static('/home/ubuntu/build/public'));
} else if (processArgs.runE2eTests) {
app.use(getExpressPath('/'), express.static(path.resolve('packer/build/public')));
} else if (platformInfo.isNpmDist) {
app.use(
getExpressPath('/'),

View File

@@ -17,12 +17,18 @@ Platform: ${process.platform}
function start() {
childProcessChecker();
process.on('message', async connection => {
// @ts-ignore
const { requestDbList } = connection;
if (handleProcessCommunication(connection)) return;
try {
const driver = requireEngineDriver(connection);
const dbhan = await connectUtility(driver, connection, 'app');
const res = await driver.getVersion(dbhan);
process.send({ msgtype: 'connected', ...res });
let databases = undefined;
if (requestDbList) {
databases = await driver.listDatabases(dbhan);
}
process.send({ msgtype: 'connected', ...res, databases });
await driver.close(dbhan);
} catch (e) {
console.error(e);

View File

@@ -258,8 +258,8 @@ async function handleCollectionData({ msgid, options }) {
return handleDriverDataCore(msgid, driver => driver.readCollection(dbhan, options), { logName: 'readCollection' });
}
async function handleLoadKeys({ msgid, root, filter }) {
return handleDriverDataCore(msgid, driver => driver.loadKeys(dbhan, root, filter), { logName: 'loadKeys' });
async function handleLoadKeys({ msgid, root, filter, limit }) {
return handleDriverDataCore(msgid, driver => driver.loadKeys(dbhan, root, filter, limit), { logName: 'loadKeys' });
}
async function handleExportKeys({ msgid, options }) {

View File

@@ -166,7 +166,9 @@ function start() {
if (time - lastPing > 40 * 1000) {
logger.info('Server connection not alive, exiting');
const driver = requireEngineDriver(storedConnection);
await driver.close(dbhan);
if (dbhan) {
await driver.close(dbhan);
}
process.exit(0);
}
}, 10 * 1000);

View File

@@ -7,7 +7,7 @@ const { getLogger, extractErrorLogData, extractErrorMessage } = require('dbgate-
const logger = getLogger('sshProcess');
async function getSshConnection(connection) {
async function getSshConnection(connection, tunnelConfig) {
const sshConfig = {
endHost: connection.sshHost || '',
endPort: connection.sshPort || 22,
@@ -23,6 +23,7 @@ async function getSshConnection(connection) {
: undefined,
skipAutoPrivateKey: true,
noReadline: true,
bindHost: tunnelConfig.fromHost,
};
const sshConn = new SSHConnection(sshConfig);
@@ -31,7 +32,7 @@ async function getSshConnection(connection) {
async function handleStart({ connection, tunnelConfig }) {
try {
const sshConn = await getSshConnection(connection);
const sshConn = await getSshConnection(connection, tunnelConfig);
await sshConn.forward(tunnelConfig);
process.send({

View File

@@ -6,6 +6,21 @@ const requireEngineDriver = require('../utility/requireEngineDriver');
const loadModelFolder = require('../utility/loadModelFolder');
const crypto = require('crypto');
/**
* Deploys database model stored in modelFolder (table as yamls) to database
* @param {object} options
* @param {connectionType} options.connection - connection object
* @param {object} options.systemConnection - system connection (result of driver.connect). If not provided, new connection will be created
* @param {object} options.driver - driver object. If not provided, it will be loaded from connection
* @param {object} options.analysedStructure - analysed structure of the database. If not provided, it will be loaded
* @param {string} options.modelFolder - folder with model files (YAML files for tables, SQL files for views, procedures, ...)
* @param {import('dbgate-tools').DatabaseModelFile[]} options.loadedDbModel - loaded database model - collection of yaml and SQL files loaded into array
* @param {function[]} options.modelTransforms - array of functions for transforming model
* @param {object} options.dbdiffOptionsExtra - extra options for dbdiff
* @param {string} options.ignoreNameRegex - regex for ignoring objects by name
* @param {string} options.targetSchema - target schema for deployment
* @param {number} options.maxMissingTablesRatio - maximum ratio of missing tables in database. Safety check, if missing ratio is highe, deploy is stopped (preventing accidental drop of all tables)
*/
async function deployDb({
connection,
systemConnection,
@@ -17,6 +32,7 @@ async function deployDb({
dbdiffOptionsExtra,
ignoreNameRegex = '',
targetSchema = null,
maxMissingTablesRatio = undefined,
}) {
if (!driver) driver = requireEngineDriver(connection);
const dbhan = systemConnection || (await connectUtility(driver, connection, 'read'));
@@ -41,6 +57,7 @@ async function deployDb({
dbdiffOptionsExtra,
ignoreNameRegex,
targetSchema,
maxMissingTablesRatio,
});
// console.log('RUNNING DEPLOY SCRIPT:', sql);
await executeQuery({ connection, systemConnection: dbhan, driver, sql, logScriptItems: true });

View File

@@ -15,6 +15,21 @@ const importDbModel = require('../utility/importDbModel');
const requireEngineDriver = require('../utility/requireEngineDriver');
const connectUtility = require('../utility/connectUtility');
/**
* Generates query for deploying model into database
* @param {object} options
* @param {connectionType} options.connection - connection object
* @param {object} options.systemConnection - system connection (result of driver.connect). If not provided, new connection will be created
* @param {object} options.driver - driver object. If not provided, it will be loaded from connection
* @param {object} options.analysedStructure - analysed structure of the database. If not provided, it will be loaded
* @param {string} options.modelFolder - folder with model files (YAML files for tables, SQL files for views, procedures, ...)
* @param {import('dbgate-tools').DatabaseModelFile[]} options.loadedDbModel - loaded database model - collection of yaml and SQL files loaded into array
* @param {function[]} options.modelTransforms - array of functions for transforming model
* @param {object} options.dbdiffOptionsExtra - extra options for dbdiff
* @param {string} options.ignoreNameRegex - regex for ignoring objects by name
* @param {string} options.targetSchema - target schema for deployment
* @param {number} options.maxMissingTablesRatio - maximum ratio of missing tables in database. Safety check, if missing ratio is highe, deploy is stopped (preventing accidental drop of all tables)
*/
async function generateDeploySql({
connection,
systemConnection = undefined,
@@ -26,25 +41,35 @@ async function generateDeploySql({
dbdiffOptionsExtra = {},
ignoreNameRegex = '',
targetSchema = null,
maxMissingTablesRatio = undefined,
}) {
if (!driver) driver = requireEngineDriver(connection);
const dbhan = systemConnection || (await connectUtility(driver, connection, 'read'));
if (
driver?.dialect?.multipleSchema &&
!targetSchema &&
dbdiffOptionsExtra?.['schemaMode'] !== 'ignore' &&
dbdiffOptionsExtra?.['schemaMode'] !== 'ignoreImplicit'
) {
throw new Error('targetSchema is required for databases with multiple schemas');
}
try {
if (!analysedStructure) {
analysedStructure = await driver.analyseFull(dbhan);
}
if (ignoreNameRegex) {
analysedStructure = skipNamesInStructureByRegex(analysedStructure, new RegExp(ignoreNameRegex, 'i'));
}
analysedStructure = skipDbGateInternalObjects(analysedStructure);
let deployedModelSource = loadedDbModel
? databaseInfoFromYamlModel(loadedDbModel)
: await importDbModel(modelFolder);
if (ignoreNameRegex) {
analysedStructure = skipNamesInStructureByRegex(analysedStructure, new RegExp(ignoreNameRegex, 'i'));
deployedModelSource = skipNamesInStructureByRegex(deployedModelSource, new RegExp(ignoreNameRegex, 'i'));
}
analysedStructure = skipDbGateInternalObjects(analysedStructure);
for (const transform of modelTransforms || []) {
deployedModelSource = transform(deployedModelSource);
}
@@ -71,6 +96,17 @@ async function generateDeploySql({
const currentModelPaired = matchPairedObjects(deployedModel, currentModel, opts);
const currentModelPairedPreloaded = await enrichWithPreloadedRows(deployedModel, currentModelPaired, dbhan, driver);
if (maxMissingTablesRatio != null) {
const missingTables = currentModelPaired.tables.filter(
x => !deployedModel.tables.find(y => y.pairingId == x.pairingId)
);
const missingTableCount = missingTables.length;
const missingTablesRatio = missingTableCount / (currentModelPaired.tables.length || 1);
if (missingTablesRatio > maxMissingTablesRatio) {
throw new Error(`Too many missing tables (${missingTablesRatio * 100}%), aborting deploy`);
}
}
// console.log('currentModelPairedPreloaded', currentModelPairedPreloaded.tables[0]);
// console.log('deployedModel', deployedModel.tables[0]);
// console.log('currentModel', currentModel.tables[0]);

View File

@@ -8,12 +8,15 @@ const logger = getLogger('tableReader');
* @param {object} options
* @param {connectionType} options.connection - connection object
* @param {object} options.systemConnection - system connection (result of driver.connect). If not provided, new connection will be created
* @param {object} options.driver - driver object. If not provided, it will be loaded from connection
* @param {string} options.pureName - table name
* @param {string} options.schemaName - schema name
* @returns {Promise<readerType>} - reader object
*/
async function tableReader({ connection, systemConnection, pureName, schemaName }) {
const driver = requireEngineDriver(connection);
async function tableReader({ connection, systemConnection, pureName, schemaName, driver }) {
if (!driver) {
driver = requireEngineDriver(connection);
}
const dbhan = systemConnection || (await connectUtility(driver, connection, 'read'));
logger.info(`Connected.`);

View File

@@ -23,6 +23,12 @@ class JsonLinesDatabase {
await fs.writeFile(this.filename, this.data.map(x => JSON.stringify(x)).join('\n'));
}
async unload() {
this.data = [];
this.loadedOk = false;
this.loadPerformed = false;
}
async _ensureLoaded() {
if (!this.loadPerformed) {
await lock.acquire('reader', async () => {
@@ -111,6 +117,15 @@ class JsonLinesDatabase {
return removed;
}
async transformAll(transformFunction) {
await this._ensureLoaded();
const newData = transformFunction(this.data);
if (newData) {
this.data = newData;
await this._save();
}
}
// async _openReader() {
// return new Promise((resolve, reject) =>
// lineReader.open(this.filename, (err, reader) => {

View File

@@ -130,7 +130,7 @@ class SSHConnection {
const connectionToBastion = await this.connect(bastionHost);
return new Promise((resolve, reject) => {
connectionToBastion.forwardOut(
'127.0.0.1',
this.options.bindHost,
22,
this.options.endHost,
this.options.endPort || 22,
@@ -228,9 +228,9 @@ class SSHConnection {
options.toPort
);
connection.forwardOut(
'localhost',
this.options.bindHost,
options.fromPort,
options.toHost || 'localhost',
options.toHost || this.options.bindHost,
options.toPort,
(error, stream) => {
if (error) {
@@ -241,7 +241,7 @@ class SSHConnection {
}
);
})
.listen(options.fromPort, 'localhost', () => {
.listen(options.fromPort, this.options.bindHost, () => {
return resolve();
});
});

View File

@@ -63,7 +63,7 @@ async function connectUtility(driver, storedConnection, connectionMode, addition
throw new Error(tunnel.message);
}
connection.server = 'localhost';
connection.server = tunnel.localHost;
connection.port = tunnel.localPort;
}

View File

@@ -96,6 +96,9 @@ function packagedPluginsDir() {
// return path.resolve(__dirname, '../../plugins');
// }
}
if (processArgs.runE2eTests) {
return path.resolve('packer/build/plugins');
}
return null;
}
@@ -110,7 +113,12 @@ function getPluginBackendPath(packageName) {
return path.join(packagedPluginsDir(), packageName, 'dist', 'backend.js');
}
return path.join(pluginsdir(), packageName, 'dist', 'backend.js');
const res = path.join(pluginsdir(), packageName, 'dist', 'backend.js');
if (fs.existsSync(res)) {
return res;
}
return require.resolve(packageName);
}
let archiveLinksCache = {};

View File

@@ -1,3 +1,5 @@
const path = require('path');
function getNamedArg(name) {
const argIndex = process.argv.indexOf(name);
if (argIndex > 0) {
@@ -14,15 +16,21 @@ const workspaceDir = getNamedArg('--workspace-dir');
const processDisplayName = getNamedArg('--process-display-name');
const listenApi = process.argv.includes('--listen-api');
const listenApiChild = process.argv.includes('--listen-api-child') || listenApi;
const runE2eTests = process.argv.includes('--run-e2e-tests');
function getPassArgs() {
const res = [];
if (global['PLUGINS_DIR']) {
res.push('--plugins-dir', global['PLUGINS_DIR']);
} else if (runE2eTests) {
res.push('--plugins-dir', path.resolve('packer/build/plugins'));
}
if (listenApiChild) {
res.push('listen-api-child');
}
// if (runE2eTests) {
// res.push('--run-e2e-tests');
// }
return res;
}
@@ -36,4 +44,5 @@ module.exports = {
listenApi,
listenApiChild,
processDisplayName,
runE2eTests,
};

View File

@@ -43,33 +43,44 @@ function callForwardProcess(connection, tunnelConfig, tunnelCacheKey) {
logger.error(extractErrorLogData(err), 'Error connecting SSH');
}
return new Promise((resolve, reject) => {
let promiseHandled = false;
subprocess.on('message', resp => {
// @ts-ignore
const { msgtype, errorMessage } = resp;
if (msgtype == 'connected') {
resolve(subprocess);
promiseHandled = true;
}
if (msgtype == 'error') {
reject(new Error(errorMessage));
promiseHandled = true;
}
});
subprocess.on('exit', code => {
logger.info('SSH forward process exited');
delete sshTunnelCache[tunnelCacheKey];
if (!promiseHandled) {
reject(new Error('SSH forward process exited, try to change "Local host address for SSH connections" in Settings/Connections'));
}
});
});
}
async function getSshTunnel(connection) {
const config = require('../controllers/config');
const tunnelCacheKey = stableStringify(_.pick(connection, TUNNEL_FIELDS));
const globalSettings = await config.getSettings();
return await lock.acquire(tunnelCacheKey, async () => {
if (sshTunnelCache[tunnelCacheKey]) return sshTunnelCache[tunnelCacheKey];
const localPort = await portfinder.getPortPromise({ port: 10000, stopPort: 60000 });
const localHost = globalSettings?.['connection.sshBindHost'] || '127.0.0.1';
// workaround for `getPortPromise` not releasing the port quickly enough
await new Promise(resolve => setTimeout(resolve, 500));
const tunnelConfig = {
fromPort: localPort,
fromHost: localHost,
toPort: connection.port,
toHost: connection.server,
};
@@ -87,6 +98,7 @@ async function getSshTunnel(connection) {
sshTunnelCache[tunnelCacheKey] = {
state: 'ok',
localPort,
localHost,
subprocess,
};
return sshTunnelCache[tunnelCacheKey];

View File

@@ -1,5 +1,5 @@
{
"version": "5.0.0-alpha.1",
"version": "6.0.0-alpha.1",
"name": "dbgate-datalib",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -13,13 +13,13 @@
"lib"
],
"dependencies": {
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-tools": "^5.0.0-alpha.1",
"dbgate-filterparser": "^5.0.0-alpha.1",
"dbgate-sqltree": "^6.0.0-alpha.1",
"dbgate-tools": "^6.0.0-alpha.1",
"dbgate-filterparser": "^6.0.0-alpha.1",
"uuid": "^3.4.0"
},
"devDependencies": {
"dbgate-types": "^5.0.0-alpha.1",
"dbgate-types": "^6.0.0-alpha.1",
"@types/node": "^13.7.0",
"jest": "^28.1.3",
"ts-jest": "^28.0.7",

View File

@@ -66,7 +66,7 @@ class DuplicatorItemHolder {
this.autoColumn = this.table.columns.find(x => x.autoIncrement)?.columnName;
if (
this.table.primaryKey?.columns?.length != 1 ||
this.table.primaryKey?.columns?.[0].columnName != this.autoColumn
this.table.primaryKey?.columns?.[0]?.columnName != this.autoColumn
) {
this.autoColumn = null;
}
@@ -140,6 +140,9 @@ class DuplicatorItemHolder {
weakref.foreignKey.columns[0].columnName
);
});
if (this.duplicator.driver.dialect.requireFromDual) {
dmp.put(' ^from ^dual');
}
});
const qrow = qres.rows[0];
return this.weakReferences.filter(x => qrow[x.columnName] == 0).map(x => x.columnName);
@@ -194,6 +197,7 @@ class DuplicatorItemHolder {
res = await runQueryOnDriver(pool, driver, dmp => dmp.selectScopeIdentity(this.table));
}
// console.log('IDRES', JSON.stringify(res));
// console.log('*********** ENTRIES OF', res?.rows?.[0]);
const resId = Object.entries(res?.rows?.[0])?.[0]?.[1];
if (resId != null) {
this.idMap[chunk[this.autoColumn]] = resId;

View File

@@ -37,7 +37,8 @@ export class TableGridDisplay extends GridDisplay {
public displayOptions: any,
serverVersion,
public getDictionaryDescription: DictionaryDescriptionFunc = null,
isReadOnly = false
isReadOnly = false,
public isRawMode = false
) {
super(config, setConfig, cache, setCache, driver, dbinfo, serverVersion);
@@ -172,6 +173,9 @@ export class TableGridDisplay extends GridDisplay {
}
addHintsToSelect(select: Select): boolean {
if (this.isRawMode) {
return false;
}
let res = false;
const groupColumns = this.groupColumns;
for (const column of this.hintBaseColumns || this.getGridColumns()) {

View File

@@ -1492,6 +1492,7 @@ export const chinookDbInfo: DatabaseInfo = {
collections: [],
matviews: [],
triggers: [],
schedulerEvents: [],
};
// const ARTIST_TABLE: TableInfo = {

View File

@@ -1,6 +1,6 @@
{
"name": "dbmodel",
"version": "5.0.0-alpha.1",
"version": "6.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",
@@ -30,16 +30,16 @@
],
"dependencies": {
"commander": "^10.0.0",
"dbgate-api": "^5.0.0-alpha.1",
"dbgate-plugin-csv": "^5.0.0-alpha.1",
"dbgate-plugin-excel": "^5.0.0-alpha.1",
"dbgate-plugin-mongo": "^5.0.0-alpha.1",
"dbgate-plugin-mssql": "^5.0.0-alpha.1",
"dbgate-plugin-mysql": "^5.0.0-alpha.1",
"dbgate-plugin-postgres": "^5.0.0-alpha.1",
"dbgate-plugin-xml": "^5.0.0-alpha.1",
"dbgate-plugin-oracle": "^5.0.0-alpha.1",
"dbgate-web": "^5.0.0-alpha.1",
"dbgate-api": "^6.0.0-alpha.1",
"dbgate-plugin-csv": "^6.0.0-alpha.1",
"dbgate-plugin-excel": "^6.0.0-alpha.1",
"dbgate-plugin-mongo": "^6.0.0-alpha.1",
"dbgate-plugin-mssql": "^6.0.0-alpha.1",
"dbgate-plugin-mysql": "^6.0.0-alpha.1",
"dbgate-plugin-postgres": "^6.0.0-alpha.1",
"dbgate-plugin-xml": "^6.0.0-alpha.1",
"dbgate-plugin-oracle": "^6.0.0-alpha.1",
"dbgate-web": "^6.0.0-alpha.1",
"dotenv": "^16.0.0",
"pinomin": "^1.0.4"
}

View File

@@ -1,5 +1,5 @@
{
"version": "5.0.0-alpha.1",
"version": "6.0.0-alpha.1",
"name": "dbgate-filterparser",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -13,7 +13,7 @@
"lib"
],
"devDependencies": {
"dbgate-types": "^5.0.0-alpha.1",
"dbgate-types": "^6.0.0-alpha.1",
"@types/jest": "^25.1.4",
"@types/node": "^13.7.0",
"jest": "^28.1.3",
@@ -22,7 +22,7 @@
},
"dependencies": {
"@types/parsimmon": "^1.10.1",
"dbgate-tools": "^5.0.0-alpha.1",
"dbgate-tools": "^6.0.0-alpha.1",
"lodash": "^4.17.21",
"date-fns": "^4.1.0",
"moment": "^2.24.0",

View File

@@ -41,7 +41,7 @@ STORAGE_DATABASE=dbname
STORAGE_ENGINE=mysql@dbgate-plugin-mysql
```
You could find more about environment variable configuration on [DbGate docs](https://dbgate.org/docs/env-variables.html) page.
You could find more about environment variable configuration on [DbGate docs](https://dbgate.org/docs/env-variables/) page.
After installing, you can run dbgate with command:
```sh

View File

@@ -1,6 +1,6 @@
{
"name": "dbgate-serve",
"version": "5.0.0-alpha.1",
"version": "6.0.0-alpha.1",
"homepage": "https://dbgate.org/",
"repository": {
"type": "git",
@@ -18,19 +18,19 @@
"web"
],
"dependencies": {
"dbgate-api": "^5.0.0-alpha.1",
"dbgate-plugin-clickhouse": "^5.0.0-alpha.1",
"dbgate-plugin-csv": "^5.0.0-alpha.1",
"dbgate-plugin-excel": "^5.0.0-alpha.1",
"dbgate-plugin-mongo": "^5.0.0-alpha.1",
"dbgate-plugin-mssql": "^5.0.0-alpha.1",
"dbgate-plugin-mysql": "^5.0.0-alpha.1",
"dbgate-plugin-oracle": "^5.0.0-alpha.1",
"dbgate-plugin-postgres": "^5.0.0-alpha.1",
"dbgate-plugin-redis": "^5.0.0-alpha.1",
"dbgate-plugin-sqlite": "^5.0.0-alpha.1",
"dbgate-plugin-xml": "^5.0.0-alpha.1",
"dbgate-web": "^5.0.0-alpha.1",
"dbgate-api": "^6.0.0-alpha.1",
"dbgate-plugin-clickhouse": "^6.0.0-alpha.1",
"dbgate-plugin-csv": "^6.0.0-alpha.1",
"dbgate-plugin-excel": "^6.0.0-alpha.1",
"dbgate-plugin-mongo": "^6.0.0-alpha.1",
"dbgate-plugin-mssql": "^6.0.0-alpha.1",
"dbgate-plugin-mysql": "^6.0.0-alpha.1",
"dbgate-plugin-oracle": "^6.0.0-alpha.1",
"dbgate-plugin-postgres": "^6.0.0-alpha.1",
"dbgate-plugin-redis": "^6.0.0-alpha.1",
"dbgate-plugin-sqlite": "^6.0.0-alpha.1",
"dbgate-plugin-xml": "^6.0.0-alpha.1",
"dbgate-web": "^6.0.0-alpha.1",
"dotenv": "^16.0.0"
}
}

View File

@@ -1,5 +1,5 @@
{
"version": "5.0.0-alpha.1",
"version": "6.0.0-alpha.1",
"name": "dbgate-sqltree",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -27,7 +27,7 @@
],
"devDependencies": {
"@types/node": "^13.7.0",
"dbgate-types": "^5.0.0-alpha.1",
"dbgate-types": "^6.0.0-alpha.1",
"typescript": "^4.4.3"
},
"dependencies": {

View File

@@ -1,5 +1,5 @@
{
"version": "5.0.0-alpha.1",
"version": "6.0.0-alpha.1",
"name": "dbgate-tools",
"main": "lib/index.js",
"typings": "lib/index.d.ts",
@@ -25,14 +25,14 @@
],
"devDependencies": {
"@types/node": "^13.7.0",
"dbgate-types": "^5.0.0-alpha.1",
"dbgate-types": "^6.0.0-alpha.1",
"jest": "^24.9.0",
"ts-jest": "^25.2.1",
"typescript": "^4.4.3"
},
"dependencies": {
"dbgate-query-splitter": "^4.11.2",
"dbgate-sqltree": "^5.0.0-alpha.1",
"dbgate-query-splitter": "^4.11.3",
"dbgate-sqltree": "^6.0.0-alpha.1",
"debug": "^4.3.4",
"json-stable-stringify": "^1.0.1",
"lodash": "^4.17.21",

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