Compare commits

...

244 Commits

Author SHA1 Message Date
bb3ca6d414 improve clickhouse driver 2022-04-19 14:21:03 +08:00
674eada9ed improve clickhouse driver 2022-04-19 14:20:00 +08:00
310baaf67d improve clickhouse driver 2022-04-19 14:18:25 +08:00
c9971b21ec improve clickhouse driver 2022-04-19 14:15:53 +08:00
be77779aff Merge branch 'master' of https://github.com/gogf/gf into develop 2022-04-18 20:29:35 +08:00
e119f2a534 improve cache handlement for package gdb 2022-04-18 20:29:24 +08:00
a09c8497bc Merge branch 'develop' of https://github.com/gogf/gf into develop 2022-04-18 20:28:14 +08:00
ebad3eb93e error meesage update for package gdb; remove default batch number for batch insert statement for package gdb 2022-04-18 20:28:00 +08:00
e4e4534c7c Merge pull request #1759 from qinyuguang/gdb_cache
fix issue #1755
2022-04-18 20:22:38 +08:00
b412fc6516 Merge pull request #1749 from qinyuguang/gjson_unmarshalvalue
fix issue #1747
2022-04-18 20:19:07 +08:00
f9c9750108 improve gutil.Dump 2022-04-15 18:00:16 +08:00
5dee3bb4d9 add auto creating tags github workflow; go.mod update for crontrib packages 2022-04-15 14:47:02 +08:00
1e3d8cdadd fix issue #1721 2022-04-13 21:58:35 +08:00
c5bf45f1ae fix issue #1755 2022-04-13 21:49:08 +08:00
bf674060c0 add internal package consts to manage shared constants; improve buildin function dump only available in develop mode for package gview 2022-04-13 21:08:12 +08:00
878dbe4ab9 fix issue #1740 2022-04-13 20:42:39 +08:00
d8b383719a improve package gtag 2022-04-13 11:21:24 +08:00
9ff5f39701 fix issue #1747 2022-04-12 23:30:18 +08:00
5144cc0e08 Merge pull request #1735 from yuancjun/patch-1
avoid a single space at the end of a line.
2022-04-12 21:36:44 +08:00
ee29b28575 improve clickhouse driver 2022-04-12 21:31:51 +08:00
7785082f19 Merge branch 'master' of https://github.com/gogf/gf into develop 2022-04-12 21:17:32 +08:00
edf40ba430 Merge pull request #1616 from DGuang21/feature-clickhouse-driver
Feature - clickhouse driver
2022-04-12 21:14:12 +08:00
a228495ced improve error message for package ghttp 2022-04-12 16:15:54 +08:00
ed9dc70769 add UT case for package gvalid 2022-04-12 16:09:24 +08:00
e8581d4fd5 add Is/Equal/Unwrap functions for package gerror 2022-04-12 15:45:26 +08:00
2d6fcf5d06 fix issue #1708 2022-04-12 12:09:09 +08:00
55e0262c37 improve package gconv 2022-04-11 21:54:23 +08:00
d5e5a48170 fix issue #1747 2022-04-11 20:49:33 +08:00
d0f2928cec fix issue of nil pointer in package internal/utils 2022-04-11 20:43:32 +08:00
190a53647e fix issue #1701 2022-04-11 20:38:48 +08:00
f9a3fa3c23 fix issue #1700 2022-04-11 17:58:07 +08:00
f1fee72d6d fix issue #1700 2022-04-08 18:11:17 +08:00
0b4ae6b116 add UpdateAndGetAffected for gdb.Model 2022-04-08 17:22:07 +08:00
a1ec7cb896 improve clickhouse driver 2022-04-08 10:08:04 +08:00
1935412db9 improve clickhouse driver 2022-04-08 10:07:14 +08:00
c90a9d45ee improve clickhouse driver 2022-04-08 09:44:42 +08:00
a594592151 Merge branch 'feature-clickhouse-driver' of https://github.com/DGuang21/gf into feature-clickhouse-driver 2022-04-08 09:43:09 +08:00
119d8bf98c improve command gf run 2022-04-07 22:07:47 +08:00
1e141d9f64 improve package gjson/ghttp 2022-04-07 21:26:39 +08:00
587af6dec8 add sqlite support for cli tool 2022-04-07 20:29:15 +08:00
793e862e5a Merge pull request #1730 from xiaoping378/patch-2
Update README.MD
2022-04-07 20:16:29 +08:00
09c3425dd3 Merge pull request #1683 from Macrow/master
feat: support custom listener
2022-04-07 20:05:16 +08:00
4ca168412b avoid a single space at the end of a line. 2022-04-06 11:57:22 +08:00
66f24db6da Update README.MD 2022-04-04 21:48:36 +08:00
c39a58f812 improve clickhouse driver 2022-04-04 14:56:44 +08:00
5034f231a9 improve clickhouse driver 2022-04-04 12:46:11 +08:00
64afd5f64c Merge branch 'master' of https://github.com/DGuang21/gf into feature-clickhouse-driver 2022-04-02 18:35:12 +08:00
0e0d2e1c45 fix: break when finished set custom listener in newGracefulServer method 2022-04-01 09:03:36 +08:00
52d8371ba9 add UT case for package gdb 2022-03-31 21:40:28 +08:00
1d74b58d36 Merge branch 'master' of https://github.com/DGuang21/gf into feature-clickhouse-driver 2022-03-31 21:29:17 +08:00
66803fd664 fix issue in package gdb 2022-03-31 16:57:32 +08:00
87609a3424 version update 2022-03-31 16:52:15 +08:00
b4184e4523 Merge branch 'master' of https://github.com/gogf/gf 2022-03-31 16:16:57 +08:00
05508e4fcb improve cache feature for package gdb 2022-03-31 16:15:44 +08:00
372bae4799 fix issue in missing first result column when in select cache scenario 2022-03-31 15:42:12 +08:00
c7f51b8e77 fix: SetListener test data race error 2022-03-30 14:55:03 +08:00
21f48d3750 improve Unique function performance for normal arrays 2022-03-30 14:32:16 +08:00
b57cbacc82 refactor: method SetListener accepts slice of net.Listener and remove method SetListeners 2022-03-29 23:22:23 +08:00
126a81d89a Merge pull request #1697 from cuishuang/master
fix some typos
2022-03-29 20:38:20 +08:00
707dc6b346 add xextensions feature for package goai 2022-03-29 20:31:00 +08:00
c1c86c026f fix type integer from type number for package goai 2022-03-28 16:40:43 +08:00
5c4982cb0c add Sort field for Pat of package goai 2022-03-28 16:20:08 +08:00
fed38ea7ab add Sort field for Operation of package goai 2022-03-28 16:18:44 +08:00
4d6ef1c52d add sort field for path of package goai 2022-03-28 15:59:02 +08:00
c6aba6da4d improve ExternalDocs feature for package goai 2022-03-28 15:21:58 +08:00
ec92d2b7f4 improve empty slice/object validation logic for package gvalid 2022-03-25 17:53:58 +08:00
6810e71220 add UT case for package goai 2022-03-25 12:00:09 +08:00
f4192d695c remove sort feature for openapi 2022-03-24 22:08:06 +08:00
6664437b06 add sort feature for path of openapi 2022-03-24 21:56:37 +08:00
96a135834a improve openapi genereating for package ghttp 2022-03-24 20:15:54 +08:00
09ba1bf1fb imrove context handling for package gdb 2022-03-24 17:51:49 +08:00
cc01629b57 improve hook and sharding feature for package gdb 2022-03-24 15:33:30 +08:00
2d586859c3 fix some typos
Signed-off-by: cuishuang <imcusg@gmail.com>
2022-03-23 21:45:00 +08:00
a5e20e4939 improve openapi paths sequence in json as api defined sequence 2022-03-23 17:39:38 +08:00
0e3f4f45e0 improve hook feature for package gdb 2022-03-23 16:23:33 +08:00
045c3e132f improve hook feature for package gdb 2022-03-23 16:17:18 +08:00
80c068ae05 add example for properties of swagger schema object 2022-03-23 15:05:37 +08:00
6574b8cbfe change build-in swagger ui to public cdn 2022-03-23 14:48:34 +08:00
20c48b1712 change build-in swagger ui to public cdn 2022-03-23 14:46:56 +08:00
ee16b6df88 change build-in swagger ui to public cdn 2022-03-23 14:43:48 +08:00
325887fa18 fix: SetListener overwrite default address 2022-03-22 21:35:53 +08:00
73ca527b0a feat: add SetListener and throw error in SetListeners 2022-03-22 13:34:15 +08:00
439350836e fix example case for package gsession 2022-03-21 22:44:21 +08:00
5ee387672b enhancement from issue #1689 2022-03-21 22:36:06 +08:00
f670c24e2c fix issue #1681 2022-03-21 22:24:59 +08:00
f2e1f63396 fix issue #1679 2022-03-21 22:04:15 +08:00
6dacdd60dc add sharding feature for package gdb 2022-03-21 21:17:48 +08:00
87ccc27ee4 sharding feature develop 2022-03-21 14:26:56 +08:00
147348e0d1 refactor: remove unnecessary code in method getListenAddress of Server 2022-03-20 10:17:44 +08:00
ad202ea735 refactor: adjust method SetListeners of server and add unit test 2022-03-20 02:31:21 +08:00
950695664c improve hook feature for package gdb 2022-03-19 23:38:57 +08:00
d1f76f3834 Merge branch 'master' of https://github.com/gogf/gf 2022-03-19 22:54:50 +08:00
66e6a05e5f cli template update 2022-03-19 22:54:38 +08:00
0f430c66ae Merge pull request #1684 from houseme/fix-1674
improve ignore and up websocket 1.5.0
2022-03-19 22:50:53 +08:00
8357b0f649 improve comment 2022-03-19 17:58:21 +08:00
7fc75bfeff improve ignore and up websocket 1.5.0 2022-03-19 16:16:18 +08:00
d7bd1b74e8 feat: support custom listener 2022-03-18 20:54:32 +08:00
d7764e2968 Merge branch 'develop' 2022-03-18 11:52:02 +08:00
f865d6fa6a remove UT case of http server in package gins 2022-03-18 10:13:00 +08:00
e6bbead4e6 Merge pull request #1660 from qinyuguang/gdb_cache
gdb returns result when cache set failed
2022-03-17 22:05:06 +08:00
5f3a525d11 add Set function for AdapterFile for package gcfg 2022-03-17 21:41:10 +08:00
c5d80a2192 improve UT cases for package gins/gvalid 2022-03-17 21:31:07 +08:00
97b8f0f781 improve recursilve validation feature for package gvalid 2022-03-17 20:27:59 +08:00
bceb5fc7de rename gdebug.TestData* -> gtest.Data*; add UT case for http server 2022-03-17 16:58:04 +08:00
b3e66d8023 improve package gjson 2022-03-15 21:45:47 +08:00
e06f831205 improve package grand 2022-03-15 17:09:35 +08:00
60340a7348 fix UT case for package glog 2022-03-15 10:15:46 +08:00
dccfc1c8cd add hook feature for model of package gdb 2022-03-14 23:47:55 +08:00
d58186372f Merge branch 'master' into develop 2022-03-14 19:43:21 +08:00
d32246275a rename DoGetAll to DoSelect 2022-03-14 19:41:32 +08:00
2eec1bc61a version updates 2022-03-14 19:39:56 +08:00
bbab9f3934 rename DoGetAll to DoSelect 2022-03-14 19:36:43 +08:00
09a3f23e3d cli pack updates 2022-03-13 09:23:19 +08:00
329f6b90f7 improve gutil.Dump feature 2022-03-11 15:26:01 +08:00
a4ab9c284f gdb returns result when cache set failed 2022-03-11 13:04:53 +08:00
9e056dfac8 Merge branch 'master' of https://github.com/gogf/gf 2022-03-11 10:24:57 +08:00
d8d9996464 fix issue #1662 2022-03-11 10:24:42 +08:00
43992a137e Merge pull request #1659 from arieslee/master
[fix bug] the default value of r.get is invalid
2022-03-11 09:14:11 +08:00
7767bf4d5d 重跑ci 2022-03-11 07:54:34 +08:00
acd1989fa1 improve Dump feature for package gutil 2022-03-10 22:29:47 +08:00
afa1f78a02 fix issue #1661 2022-03-10 21:12:24 +08:00
87b1433473 issue template update 2022-03-10 19:30:03 +08:00
5813979479 重跑ci 2022-03-10 14:32:06 +08:00
ba7cbfe3d9 error message update for database driver import 2022-03-10 14:29:49 +08:00
546b6b1724 t.Assert(err, nil) -> t.AssertNil(err) 2022-03-10 11:36:40 +08:00
eca3583845 fix issue #1416; add ParseOption for package gview 2022-03-10 11:35:23 +08:00
2471130f59 重跑ci 2022-03-10 09:52:45 +08:00
f5693c4393 improve package gview 2022-03-10 09:48:19 +08:00
12eb3ac63e [fix bug] the default value of r.get is invalid 2022-03-10 09:33:33 +08:00
e3f0163092 Merge branch 'master' of https://github.com/gogf/gf 2022-03-10 09:23:01 +08:00
213392640c fix issue #1653 2022-03-10 09:22:50 +08:00
4382a6e7bc Merge pull request #1658 from houseme/fix-1655
fix: js link err
2022-03-10 09:14:38 +08:00
c200177af4 fix: js link err 2022-03-09 23:36:30 +08:00
465100ae41 Merge pull request #1657 from houseme/fix-1655
fix: server access logs contain the protocol used between the server …
2022-03-09 22:23:40 +08:00
3d6867c321 fix 2022-03-09 21:29:49 +08:00
3d5ff3b250 fix 2022-03-09 21:27:02 +08:00
be47203732 improve code 2022-03-09 21:24:57 +08:00
1625fc6f7e improve order feature for gdb.Model 2022-03-09 21:02:08 +08:00
fa57634505 Merge pull request #1529 from zxr615/feature-groupRaw
Added Order() method support for gdb.
2022-03-09 20:55:15 +08:00
ac71658b4b Merge branch 'master' into feature-groupRaw 2022-03-09 20:55:06 +08:00
61db7d96b7 Merge pull request #1520 from FlyingBlazer/patch-1
Fix gdb Order
2022-03-09 20:48:54 +08:00
5ee297d999 Merge pull request #1651 from chenzebinm4/develop/bert
Repeat 'len(s)'.
2022-03-09 20:46:41 +08:00
6301403777 Merge pull request #1632 from huangqian1985/master
Improving gfile and gSesssion Code Coverage
2022-03-09 20:45:44 +08:00
95881d7616 Merge pull request #1652 from stardemo/master
[fix] gf cli build missing suffix
2022-03-09 20:43:40 +08:00
85d8f90d81 Merge pull request #1656 from tiger1103/master
[fix bug] Fix redis cache adapter GetOrSetFunc, GetOrSetFuncLock meth…
2022-03-09 20:42:44 +08:00
f6054ab37f improve code 2022-03-09 18:32:13 +08:00
5537930210 fix 2022-03-09 18:30:32 +08:00
920dbbef5e fix: server access logs contain the protocol used between the server and the load balancer, but not the protocol used between the client and the load balancer 2022-03-09 17:42:56 +08:00
yxh
2510e0412d [fix bug] Fix redis cache adapter GetOrSetFunc, GetOrSetFuncLock method bug and add unit test 2022-03-09 17:21:02 +08:00
2302f88847 [fix] gf cli build missing suffix 2022-03-09 11:27:52 +08:00
4f95d0a07a Repeat 'len(s)'. 2022-03-09 10:53:28 +08:00
8f326dcac5 project template update 2022-03-08 22:51:56 +08:00
aa294ea5df ci updates 2022-03-08 21:27:14 +08:00
6afc725b61 ci updates 2022-03-08 21:22:01 +08:00
ec01693773 ci updates 2022-03-08 21:04:48 +08:00
b0cf501782 ci updates 2022-03-08 20:28:18 +08:00
c2fb7ada0a improve example for package gmap 2022-03-08 20:25:34 +08:00
d0a8e60ace improve example for package gmap 2022-03-08 20:14:38 +08:00
ab36bb8842 version updates 2022-03-08 20:12:48 +08:00
0b3cd7b7ae improve handler response for ghttp.Server 2022-03-08 11:50:23 +08:00
10ed04cdb8 example updates for package gmap 2022-03-08 09:49:33 +08:00
f08c18594b Merge branch 'master' of https://github.com/gogf/gf 2022-03-07 22:35:39 +08:00
e09704a408 example updates for package gmap 2022-03-07 22:10:34 +08:00
ade9ae3c0b improve package goai 2022-03-07 21:29:37 +08:00
9cf6124c4c improve package goai 2022-03-07 21:09:02 +08:00
6d323cc529 improve package goai 2022-03-07 20:49:30 +08:00
aea9f6fe18 keep sequence in attributes definition for oai.Schemas 2022-03-07 19:46:05 +08:00
8a27463e44 ensure sequence for json.Marshal for gmap.ListMap/TreeMap 2022-03-07 17:39:41 +08:00
47ee2cba51 Merge branch 'master' of https://github.com/gogf/gf 2022-03-07 09:58:07 +08:00
531cc7b864 fix issue in package gproc 2022-03-07 09:57:51 +08:00
54bdabd94d Merge pull request #1549 from FlyingBlazer/cookie-secure-config
ghttp: add cookie security configurations
2022-03-04 17:42:44 +08:00
bb6e8fe7a8 Merge branch 'master' of https://github.com/gogf/gf 2022-03-04 11:37:30 +08:00
d5d199ebef Swagger UI updates 2022-03-04 11:36:05 +08:00
158a4589d2 Merge pull request #1637 from wangbs95/feature/fix-chinese-encode
fix(fix bug , add nexttime feature): ServeFileDownload filename doubl…
2022-03-04 09:32:01 +08:00
84c0f456c0 template pack update 2022-03-03 21:43:01 +08:00
3fcd6ef877 fix issue orphan value parsing for sructured arguments of command for package gcmd 2022-03-03 21:03:42 +08:00
b5855037f3 Improving gSession Code Coverage 2022-03-02 21:50:23 +08:00
4e2d378145 improve file uploading using strict route feature 2022-03-02 21:15:16 +08:00
38a7055017 Merge branch 'master' of https://github.com/gogf/gf 2022-03-02 21:05:14 +08:00
d64898c59a improve package goai 2022-03-02 20:00:40 +08:00
3bff71b3fc merge master and update unit test 2022-03-02 15:33:58 +08:00
8343d1cd0e Merge branch 'master' into cookie-secure-config 2022-03-02 15:20:31 +08:00
5c23c0cecd fix(fix bug , add nexttime feature): ServeFileDownload filename double quotes cause underscores before and after the final file 2022-03-02 11:00:04 +08:00
f580713478 Merge branch 'master' of https://github.com/gogf/gf 2022-03-02 10:26:20 +08:00
3c58b8d7fa improve openapi 2022-03-02 10:26:09 +08:00
072d5f9760 make options public 2022-03-02 09:56:58 +08:00
f8067f5dd5 improve package ghttp 2022-03-01 22:53:19 +08:00
ea354d10cc Merge pull request #1636 from wangbs95/feature/fix-chinese-encode
revert(fix bug , add nexttime feature): ServeFileDownload File name C…
2022-03-01 22:52:34 +08:00
4d5b41434a Merge branch 'master' of https://github.com/gogf/gf 2022-03-01 22:38:51 +08:00
1724a26957 improve package gcfg 2022-03-01 22:34:57 +08:00
cb69fbcbd6 Improving gSession Code Coverage 2022-03-01 22:12:59 +08:00
46dc68dfd5 CI update for gf cli 2022-03-01 21:20:17 +08:00
12fdfbf8b2 improve package gcfg 2022-03-01 21:14:45 +08:00
992a986d12 Merge branch 'master' of https://github.com/gogf/gf 2022-03-01 20:02:21 +08:00
68bdf7deb4 revert(fix bug , add nexttime feature): ServeFileDownload File name Chinese garbled repair 2022-03-01 18:32:11 +08:00
2362c453ec improve cli command install 2022-03-01 16:39:47 +08:00
50f6b6e0f0 fix UT case for package ghttp 2022-03-01 14:08:36 +08:00
88a9eef8a6 api swagger ui update 2022-03-01 11:43:42 +08:00
eb533f3344 Improving gfile Code Coverage 2022-02-28 22:57:53 +08:00
308e13a546 gf cli command build update 2022-02-28 22:00:25 +08:00
a0b1fefdbb Merge branch 'master' of https://github.com/gogf/gf 2022-02-28 21:58:15 +08:00
3edbcb7bf9 gf cli update 2022-02-28 21:57:59 +08:00
436931b560 Merge branch 'master' of https://github.com/gogf/gf 2022-02-28 21:15:15 +08:00
0516159ae3 Improving gcmd Code Coverage 2022-02-28 21:11:53 +08:00
cb78953b38 Merge pull request #1628 from huangqian1985/master
Improving gcmd Code Coverage
2022-02-28 20:45:01 +08:00
a1ddac4e6b Merge branch 'master' of https://github.com/gogf/gf 2022-02-28 17:49:16 +08:00
456697ea99 improve cli command install 2022-02-28 17:48:52 +08:00
8acffd1186 Improving gcmd Code Coverage 2022-02-27 21:00:23 +08:00
814450fd17 gcmd example 2022-02-27 13:22:26 +08:00
1365c1d277 Merge pull request #1623 from huangqian1985/master
Improving gjson Code Coverage
2022-02-27 08:59:19 +08:00
30be5c5e49 Improving gjson Code Coverage And Fix 2022-02-26 21:26:30 +08:00
932cd9d5bb README updates 2022-02-25 10:22:54 +08:00
7b5f17c16b gf cli pack template update 2022-02-24 22:44:48 +08:00
b5e8e68713 fix issue #1625 2022-02-24 22:07:27 +08:00
3a803ac39f fix 2022-02-24 21:41:39 +08:00
d27db119a0 fix issue #1626 2022-02-24 21:24:42 +08:00
f54d0a339c Improving gjson Code Coverage 2022-02-24 21:14:11 +08:00
5e3c0bd9aa improve clickhouse driver 2022-02-24 21:06:26 +08:00
d83b676c60 Merge branch 'gjson_example' 2022-02-24 20:15:55 +08:00
def3dc364f Merge branch 'master' of https://github.com/gogf/gf 2022-02-24 20:15:44 +08:00
298aa5f040 Improving gjson Code Coverage 2022-02-24 20:14:44 +08:00
a6bbb8424c improve clickhouse driver 2022-02-24 13:50:28 +08:00
00daeb318c improve clickhouse driver 2022-02-24 13:03:01 +08:00
65341141fe improve clickhouse driver 2022-02-24 12:58:57 +08:00
fe353c5fe3 Merge branch 'gogf:master' into feature-clickhouse-driver 2022-02-24 10:12:05 +08:00
008e5ea196 improve clickhouse driver 2022-02-23 22:53:28 +08:00
157e936f24 improve clickhouse driver 2022-02-23 22:51:37 +08:00
e4d56e7ad9 improve package gjson 2022-02-23 16:54:15 +08:00
0fce4edcd3 Merge branch 'master' of https://github.com/gogf/gf 2022-02-23 00:46:47 +08:00
a34f52ae5e Merge branch 'gjson_example' 2022-02-23 00:46:33 +08:00
da465bb030 Improving gjson Code Coverage 2022-02-23 00:46:13 +08:00
455d724c01 improve clickhouse driver 2022-02-19 23:10:31 +08:00
ea60f7e054 improve clickhouse driver 2022-02-19 17:49:53 +08:00
daf2b649ef improve clickhouse driver 2022-02-19 16:59:17 +08:00
aa87d234e3 improve clickhouse driver 2022-02-19 15:09:44 +08:00
658ca8c0fd Eg 2022-01-17 17:14:40 +08:00
d30862373e 修正测试数据库配置 2022-01-07 22:25:00 +08:00
ee4ca43bd5 Safe() 2022-01-07 22:21:18 +08:00
0dc1adb672 orderBy raw() 2022-01-07 21:06:49 +08:00
d045b4d2f5 make unit test compatible with go 1.15 2022-01-07 18:52:21 +08:00
572e71d76a add CookieOptions
add UnitTest
2022-01-07 17:10:21 +08:00
c91b83969c WIP: add cookie security configuration 2022-01-05 14:33:20 +08:00
47cefbf6d7 允许多次调用Order 2022-01-05 11:53:50 +08:00
b39b2374c4 Added Order() method support for gdb. 2021-12-22 20:51:03 +08:00
374 changed files with 8494 additions and 3162 deletions

View File

@ -1,12 +1,11 @@
<!-- Please answer these questions before submitting your issue. Thanks! -->
<!-- 为高效处理您的疑问如果觉得是BUG类问题请您务必提供可复现该问题的最小可运行代码 -->
<!-- 为高效处理您的疑问如果觉得是BUG类问题请您务必提供可复现该问题的最小可运行代码 -->
<!-- 为高效处理您的疑问如果觉得是BUG类问题请您务必提供可复现该问题的最小可运行代码 -->
<!-- 为高效处理您的疑问如果觉得是BUG类问题请您务必提供可复现该问题的最小可运行代码否则issue可能会被延期处理 -->
<!-- 为高效处理您的疑问如果觉得是BUG类问题请您务必提供可复现该问题的最小可运行代码否则issue可能会被延期处理 -->
<!-- 为高效处理您的疑问如果觉得是BUG类问题请您务必提供可复现该问题的最小可运行代码否则issue可能会被延期处理 -->
<!-- 重要的事情说三遍! -->
### 1. What version of `Go` and system type/arch are you using?
<!--
Please paste the output of command `go version` from your terminal.
What expect to see is like: `go 1.12, linux/amd64`
@ -14,7 +13,6 @@ What expect to see is like: `go 1.12, linux/amd64`
### 2. What version of `GoFrame` are you using?
<!-- You can find the GF version from your `go.mod`, or from the `version.go` in `GF` -->
@ -23,7 +21,6 @@ What expect to see is like: `go 1.12, linux/amd64`
### 4. What did you do?
<!--
If possible, provide a copy of shortest codes for reproducing the error.
A complete runnable program is best.

View File

@ -6,6 +6,10 @@ on:
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
env:
TZ: Asia/Shanghai
jobs:
build:
name: Build And Release
@ -26,37 +30,21 @@ jobs:
GOOS=linux GOARCH=amd64 go build main.go
chmod +x main
./main install -y
# gf build
- name: Build CLI Binary For All Platform
run: |
cd cmd/gf
gf build main.go -n gf -a all -s all
# 处理gf-cli批量编译后的文件结构
- name: Move Files Before Upx
- name: Move Files Before Release
run: |
cd cmd/gf/bin
cd cmd/gf/temp
for OS in *;do for FILE in $OS/*;\
do if [[ ${OS} =~ 'windows' ]];\
then rm -rf noupx && mkdir noupx && mv $FILE noupx/gf_$OS.exe && rm -rf $OS;\
then mv $FILE gf_$OS.exe && rm -rf $OS;\
else mv $FILE gf_$OS && rm -rf $OS;\
fi;done;done
# UPX 加壳所有文件
- name: Upx All Binary
uses: gacts/upx@master
with:
dir: 'cmd/gf/bin'
upx_args: '-9'
# 移动未UPX的windows程序到上传bin目录下
- name: Move Files After Upx
run: |
cd cmd/gf/bin
mv noupx/* ./ && rm -rf noupx
ls -l
- name: Create Github Release
id: create_release
uses: actions/create-release@v1
@ -74,4 +62,4 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
asset_paths: '["cmd/gf/bin/gf_*"]'
asset_paths: '["cmd/gf/temp/gf_*"]'

View File

@ -1,4 +1,4 @@
name: GoFrame CI
name: GoFrame Main CI
on:
@ -76,11 +76,18 @@ jobs:
--health-timeout 5s
--health-retries 10
clickhouse-server:
image: yandex/clickhouse-server
ports:
- 9000:9000
- 8123:8123
- 9001:9001
# strategy set
strategy:
matrix:
go: ["1.15", "1.16", "1.17"]
go: ["1.16", "1.17"]
steps:
@ -89,7 +96,7 @@ jobs:
with:
timezoneLinux: "Asia/Shanghai"
- name: Checkout Repositary
- name: Checkout Repository
uses: actions/checkout@v2
- name: Set Up Go

30
.github/workflows/tag.yml vendored Normal file
View File

@ -0,0 +1,30 @@
name: GoFrame AutoCreating SubMod Tags
on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
env:
TZ: Asia/Shanghai
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build:
name: Auto Creating Tags
runs-on: ubuntu-latest
steps:
- name: Checkout Github Code
uses: actions/checkout@v2
- name: Auto Creating Tags
run: |
git config --global user.email "tagrobot@goframe.org"
git config --global user.name "TagRobot"
for file in `find contrib -name go.mod`; do
tag=$(dirname $file)/$GITHUB_REF_NAME
git tag $tag
git push origin $tag
done

1
.gitignore vendored
View File

@ -13,7 +13,6 @@ pkg/
bin/
cbuild
**/.DS_Store
.vscode/
.test/
main
gf

View File

@ -5,28 +5,27 @@
## 1. Install
## 1) PreCompiled Binary
You can also install `gf` tool using pre-built binaries: https://github.com/gogf/gf/releases
1. `Mac`
1. `Mac` & `Linux`
```shell
# Intel.
wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_darwin_amd64 && chmod +x gf && ./gf install && rm ./gf
# M1.
wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_darwin_arm64 && chmod +x gf && ./gf install && rm ./gf
wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(go env GOOS)_$(go env GOARCH) && chmod +x gf && ./gf install -y && rm ./gf
```
> If you're using `zsh`, you might need rename your alias by command `alias gf=gf` to resolve the conflicts between `gf` and `git fetch`.
2. `Linux`
```shell
wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_linux_amd64 && chmod +x gf && ./gf install && rm ./gf
```
3. `Windows`
2. `Windows`
Manually download, execute it and then follow the instruction.
4. Database `sqlite` and `oracle` are not support in `gf gen` command in default as it needs `cgo` and `gcc`, you can manually make some changes to the source codes and do the building.
3. Database `sqlite` and `oracle` are not support in `gf gen` command in default as it needs `cgo` and `gcc`, you can manually make some changes to the source codes and do the building.
## 2) Manually Install
```shell
git clone https://github.com/gogf/gf && cd gf/cmd/gf && go install
```
## 2. Commands
```html

View File

@ -3,15 +3,17 @@ module github.com/gogf/gf/cmd/gf/v2
go 1.15
require (
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.0.0-rc2
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.0.0-rc2
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.0.0-rc2
github.com/gogf/gf/v2 v2.0.0-rc
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.0.6
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.0.6
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.0.6
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.0.6
github.com/gogf/gf/v2 v2.0.6
github.com/olekukonko/tablewriter v0.0.5
)
replace (
github.com/gogf/gf/contrib/drivers/mssql/v2 => ../../contrib/drivers/mssql/
github.com/gogf/gf/contrib/drivers/oracle/v2 => ../../contrib/drivers/oracle/
github.com/gogf/gf/contrib/drivers/pgsql/v2 => ../../contrib/drivers/pgsql/
github.com/gogf/gf/contrib/drivers/sqlite/v2 => ../../contrib/drivers/sqlite/
github.com/gogf/gf/v2 => ../../

View File

@ -22,6 +22,8 @@ github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Px
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@ -40,18 +42,22 @@ github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/longbridgeapp/sqlparser v0.3.1 h1:iWOZWGIFgQrJRgobLXUNJdvqGRpbVXkyKUKUA5CNJBE=
github.com/longbridgeapp/sqlparser v0.3.1/go.mod h1:GIHaUq8zvYyHLCLMJJykx1CdM6LHtkUih/QaJXySSx4=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-oci8 v0.1.1 h1:aEUDxNAyDG0tv8CA3TArnDQNyc4EhnWlsfxRgDHABHM=
github.com/mattn/go-oci8 v0.1.1/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk=

View File

@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"os"
"regexp"
"runtime"
"strings"
@ -24,7 +25,7 @@ import (
var (
Build = cBuild{
nodeNameInConfigFile: "gfcli.build",
packedGoFileName: "build_pack_data.go",
packedGoFileName: "internal/packed/build_pack_data.go",
}
)
@ -107,19 +108,21 @@ func init() {
}
type cBuildInput struct {
g.Meta `name:"build" config:"gfcli.build"`
File string `name:"FILE" arg:"true" brief:"building file path"`
Name string `short:"n" name:"name" brief:"output binary name"`
Version string `short:"v" name:"version" brief:"output binary version"`
Arch string `short:"a" name:"arch" brief:"output binary architecture, multiple arch separated with ','"`
System string `short:"s" name:"system" brief:"output binary system, multiple os separated with ','"`
Output string `short:"o" name:"output" brief:"output binary path, used when building single binary file"`
Path string `short:"p" name:"path" brief:"output binary directory path, default is './bin'" d:"./bin"`
Extra string `short:"e" name:"extra" brief:"extra custom \"go build\" options"`
Mod string `short:"m" name:"mod" brief:"like \"-mod\" option of \"go build\", use \"-m none\" to disable go module"`
Cgo bool `short:"c" name:"cgo" brief:"enable or disable cgo feature, it's disabled in default" orphan:"true"`
VarMap g.Map `short:"r" name:"varMap" brief:"custom built embedded variable into binary"`
Pack string `name:"pack" brief:"pack specified folder into temporary go file before building and removes it after built"`
g.Meta `name:"build" config:"gfcli.build"`
File string `name:"FILE" arg:"true" brief:"building file path"`
Name string `short:"n" name:"name" brief:"output binary name"`
Version string `short:"v" name:"version" brief:"output binary version"`
Arch string `short:"a" name:"arch" brief:"output binary architecture, multiple arch separated with ','"`
System string `short:"s" name:"system" brief:"output binary system, multiple os separated with ','"`
Output string `short:"o" name:"output" brief:"output binary path, used when building single binary file"`
Path string `short:"p" name:"path" brief:"output binary directory path, default is './temp'" d:"./temp"`
Extra string `short:"e" name:"extra" brief:"extra custom \"go build\" options"`
Mod string `short:"m" name:"mod" brief:"like \"-mod\" option of \"go build\", use \"-m none\" to disable go module"`
Cgo bool `short:"c" name:"cgo" brief:"enable or disable cgo feature, it's disabled in default" orphan:"true"`
VarMap g.Map `short:"r" name:"varMap" brief:"custom built embedded variable into binary"`
PackSrc string `short:"ps" name:"packSrc" brief:"pack one or more folders into one go file before building"`
PackDst string `short:"pd" name:"packDst" brief:"temporary go file path for pack, this go file will be automatically removed after built" d:"internal/packed/build_pack_data.go"`
ExitWhenError bool `short:"ew" name:"exitWhenError" brief:"exit building when any error occurs, default is false" orphan:"true"`
}
type cBuildOutput struct{}
@ -187,16 +190,21 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
platformMap[system][arch] = true
}
// Auto packing.
if len(in.Pack) > 0 {
dataFilePath := fmt.Sprintf(`packed/%s`, c.packedGoFileName)
if !gfile.Exists(dataFilePath) {
if in.PackSrc != "" {
if in.PackDst == "" {
mlog.Fatal(`parameter "packDst" should not be empty when "packSrc" is used`)
}
if gfile.Exists(in.PackDst) && !gfile.IsFile(in.PackDst) {
mlog.Fatalf(`parameter "packDst" path "%s" should be type of file not directory`, in.PackDst)
}
if !gfile.Exists(in.PackDst) {
// Remove the go file that is automatically packed resource.
defer func() {
_ = gfile.Remove(dataFilePath)
mlog.Printf(`remove the automatically generated resource go file: %s`, dataFilePath)
_ = gfile.Remove(in.PackDst)
mlog.Printf(`remove the automatically generated resource go file: %s`, in.PackDst)
}()
}
packCmd := fmt.Sprintf(`gf pack %s %s`, in.Pack, dataFilePath)
packCmd := fmt.Sprintf(`gf pack %s %s`, in.PackSrc, in.PackDst)
mlog.Print(packCmd)
gproc.MustShellRun(packCmd)
}
@ -254,7 +262,14 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
mlog.Print(cmdShow)
if result, err := gproc.ShellExec(cmd); err != nil {
mlog.Printf("failed to build, os:%s, arch:%s, error:\n%s\n", system, arch, gstr.Trim(result))
mlog.Printf(
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
system, arch, gstr.Trim(result),
`you may use command option "--debug" to enable debug info and check the details`,
)
if in.ExitWhenError {
os.Exit(1)
}
} else {
mlog.Debug(gstr.Trim(result))
}
@ -264,6 +279,7 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
}
}
}
buildDone:
mlog.Print("done!")
return

View File

@ -81,6 +81,7 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
}
// Binary build.
in.Build += " --exit"
if in.Main != "" {
if err = gproc.ShellRun(fmt.Sprintf(`gf build %s %s`, in.Main, in.Build)); err != nil {
return

View File

@ -35,7 +35,7 @@ const (
cGenDaoEg = `
gf gen dao
gf gen dao -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
gf gen dao -p ./model -c config.yaml -g user-center -t user,user_detail,user_login
gf gen dao -p ./model -g user-center -t user,user_detail,user_login
gf gen dao -r user_
`

View File

@ -13,6 +13,7 @@ import (
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
)
@ -149,9 +150,9 @@ func (app *cRunApp) Run() {
if runtime.GOOS == "windows" {
// Special handling for windows platform.
// DO NOT USE "cmd /c" command.
process = gproc.NewProcess(runCommand, nil)
process = gproc.NewProcess(outputPath, gstr.SplitAndTrim(" ", app.Args))
} else {
process = gproc.NewProcessCmd(runCommand, nil)
process = gproc.NewProcessCmd(outputPath, gstr.SplitAndTrim(" ", app.Args))
}
if pid, err := process.Start(); err != nil {
mlog.Printf("build running error: %s", err.Error())

View File

@ -11,10 +11,13 @@ import (
"{TplImportPrefix}/internal"
)
// internal{TplTableNameCamelCase}Dao is internal type for wrapping internal DAO implements.
type internal{TplTableNameCamelCase}Dao = *internal.{TplTableNameCamelCase}Dao
// {TplTableNameCamelLowerCase}Dao is the data access object for table {TplTableName}.
// You can define custom methods on it to extend its functionality as you wish.
type {TplTableNameCamelLowerCase}Dao struct {
*internal.{TplTableNameCamelCase}Dao
internal{TplTableNameCamelCase}Dao
}
var (

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -32,7 +32,7 @@ type serviceInstallAvailablePath struct {
func (s serviceInstall) Run(ctx context.Context) (err error) {
// Ask where to install.
paths := s.getInstallPathsData()
paths := s.getAvailablePaths()
if len(paths) <= 0 {
mlog.Printf("no path detected, you can manually install gf by copying the binary to path folder.")
return
@ -43,16 +43,21 @@ func (s serviceInstall) Run(ctx context.Context) (err error) {
// Print all paths status and determine the default selectedID value.
var (
selectedID = -1
newPaths []serviceInstallAvailablePath
pathSet = gset.NewStrSet() // Used for repeated items filtering.
)
for id, aPath := range paths {
if !pathSet.AddIfNotExist(aPath.dirPath) {
for _, path := range paths {
if !pathSet.AddIfNotExist(path.dirPath) {
continue
}
mlog.Printf(" %2d | %8t | %9t | %s", id, aPath.writable, aPath.installed, aPath.dirPath)
newPaths = append(newPaths, path)
}
paths = newPaths
for id, path := range paths {
mlog.Printf(" %2d | %8t | %9t | %s", id, path.writable, path.installed, path.dirPath)
if selectedID == -1 {
// Use the previously installed path as the most priority choice.
if aPath.installed {
if path.installed {
selectedID = id
}
}
@ -61,6 +66,7 @@ func (s serviceInstall) Run(ctx context.Context) (err error) {
if selectedID == -1 {
// Order by choosing priority.
commonPaths := garray.NewStrArrayFrom(g.SliceStr{
s.getGoPathBin(),
`/usr/local/bin`,
`/usr/bin`,
`/usr/sbin`,
@ -121,10 +127,10 @@ func (s serviceInstall) Run(ctx context.Context) (err error) {
}
// Uninstall the old binary.
for _, aPath := range paths {
for _, path := range paths {
// Do not delete myself.
if aPath.filePath != "" && aPath.filePath != dstPath.filePath && gfile.SelfPath() != aPath.filePath {
_ = gfile.Remove(aPath.filePath)
if path.filePath != "" && path.filePath != dstPath.filePath && gfile.SelfPath() != path.filePath {
_ = gfile.Remove(path.filePath)
}
}
return
@ -132,7 +138,7 @@ func (s serviceInstall) Run(ctx context.Context) (err error) {
// IsInstalled checks and returns whether the binary is installed.
func (s serviceInstall) IsInstalled() bool {
paths := s.getInstallPathsData()
paths := s.getAvailablePaths()
for _, aPath := range paths {
if aPath.installed {
return true
@ -141,11 +147,26 @@ func (s serviceInstall) IsInstalled() bool {
return false
}
// GetInstallPathsData returns the installation paths data for the binary.
func (s serviceInstall) getInstallPathsData() []serviceInstallAvailablePath {
var folderPaths []serviceInstallAvailablePath
// Pre generate binaryFileName.
binaryFileName := "gf" + gfile.Ext(gfile.SelfPath())
// getGoPathBinFilePath retrieves ad returns the GOPATH/bin path for binary.
func (s serviceInstall) getGoPathBin() string {
if goPath := genv.Get(`GOPATH`).String(); goPath != "" {
return gfile.Join(goPath, "bin")
}
return ""
}
// getAvailablePaths returns the installation paths data for the binary.
func (s serviceInstall) getAvailablePaths() []serviceInstallAvailablePath {
var (
folderPaths []serviceInstallAvailablePath
binaryFileName = "gf" + gfile.Ext(gfile.SelfPath())
)
// $GOPATH/bin
if goPathBin := s.getGoPathBin(); goPathBin != "" {
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, goPathBin, binaryFileName,
)
}
switch runtime.GOOS {
case "darwin":
darwinInstallationCheckPaths := []string{"/usr/local/bin"}
@ -157,21 +178,24 @@ func (s serviceInstall) getInstallPathsData() []serviceInstallAvailablePath {
fallthrough
default:
// $GOPATH/bin
gopath := gfile.Join(runtime.GOROOT(), "bin")
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, gopath, binaryFileName,
)
// Search and find the writable directory path.
envPath := genv.Get("PATH", genv.Get("Path").String()).String()
if gstr.Contains(envPath, ";") {
// windows.
for _, v := range gstr.SplitAndTrim(envPath, ";") {
if v == "." {
continue
}
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, v, binaryFileName,
)
}
} else if gstr.Contains(envPath, ":") {
// *nix.
for _, v := range gstr.SplitAndTrim(envPath, ":") {
if v == "." {
continue
}
folderPaths = s.checkAndAppendToAvailablePath(
folderPaths, v, binaryFileName,
)

View File

@ -3,7 +3,6 @@ package mlog
import (
"context"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/glog"
@ -36,9 +35,9 @@ func init() {
func SetHeaderPrint(enabled bool) {
logger.SetHeaderPrint(enabled)
if enabled {
genv.Set(headerPrintEnvName, "1")
_ = genv.Set(headerPrintEnvName, "1")
} else {
genv.Set(headerPrintEnvName, "0")
_ = genv.Set(headerPrintEnvName, "0")
}
}
@ -51,17 +50,17 @@ func Printf(format string, v ...interface{}) {
}
func Fatal(v ...interface{}) {
logger.Fatal(ctx, append(g.Slice{"ERROR:"}, v...)...)
logger.Fatal(ctx, v...)
}
func Fatalf(format string, v ...interface{}) {
logger.Fatalf(ctx, "ERROR: "+format, v...)
logger.Fatalf(ctx, format, v...)
}
func Debug(v ...interface{}) {
logger.Debug(ctx, append(g.Slice{"DEBUG:"}, v...)...)
logger.Debug(ctx, v...)
}
func Debugf(format string, v ...interface{}) {
logger.Debugf(ctx, "DEBUG: "+format, v...)
logger.Debugf(ctx, format, v...)
}

View File

@ -503,16 +503,25 @@ func (a *Array) Search(value interface{}) int {
// Example: [1,1,2,3,2] -> [1,2,3]
func (a *Array) Unique() *Array {
a.mu.Lock()
for i := 0; i < len(a.array)-1; i++ {
for j := i + 1; j < len(a.array); {
if a.array[i] == a.array[j] {
a.array = append(a.array[:j], a.array[j+1:]...)
} else {
j++
}
}
defer a.mu.Unlock()
if len(a.array) == 0 {
return a
}
a.mu.Unlock()
var (
ok bool
temp interface{}
uniqueSet = make(map[interface{}]struct{})
uniqueArray = make([]interface{}, 0, len(a.array))
)
for i := 0; i < len(a.array); i++ {
temp = a.array[i]
if _, ok = uniqueSet[temp]; ok {
continue
}
uniqueSet[temp] = struct{}{}
uniqueArray = append(uniqueArray, temp)
}
a.array = uniqueArray
return a
}
@ -711,6 +720,9 @@ func (a *Array) IteratorDesc(f func(k int, v interface{}) bool) {
// String returns current array as a string, which implements like json.Marshal does.
func (a *Array) String() string {
if a == nil {
return ""
}
a.mu.RLock()
defer a.mu.RUnlock()
buffer := bytes.NewBuffer(nil)

View File

@ -514,16 +514,25 @@ func (a *IntArray) Search(value int) int {
// Example: [1,1,2,3,2] -> [1,2,3]
func (a *IntArray) Unique() *IntArray {
a.mu.Lock()
for i := 0; i < len(a.array)-1; i++ {
for j := i + 1; j < len(a.array); {
if a.array[i] == a.array[j] {
a.array = append(a.array[:j], a.array[j+1:]...)
} else {
j++
}
}
defer a.mu.Unlock()
if len(a.array) == 0 {
return a
}
a.mu.Unlock()
var (
ok bool
temp int
uniqueSet = make(map[int]struct{})
uniqueArray = make([]int, 0, len(a.array))
)
for i := 0; i < len(a.array); i++ {
temp = a.array[i]
if _, ok = uniqueSet[temp]; ok {
continue
}
uniqueSet[temp] = struct{}{}
uniqueArray = append(uniqueArray, temp)
}
a.array = uniqueArray
return a
}
@ -722,6 +731,9 @@ func (a *IntArray) IteratorDesc(f func(k int, v int) bool) {
// String returns current array as a string, which implements like json.Marshal does.
func (a *IntArray) String() string {
if a == nil {
return ""
}
return "[" + a.Join(",") + "]"
}

View File

@ -516,16 +516,25 @@ func (a *StrArray) Search(value string) int {
// Example: [1,1,2,3,2] -> [1,2,3]
func (a *StrArray) Unique() *StrArray {
a.mu.Lock()
for i := 0; i < len(a.array)-1; i++ {
for j := i + 1; j < len(a.array); {
if a.array[i] == a.array[j] {
a.array = append(a.array[:j], a.array[j+1:]...)
} else {
j++
}
}
defer a.mu.Unlock()
if len(a.array) == 0 {
return a
}
a.mu.Unlock()
var (
ok bool
temp string
uniqueSet = make(map[string]struct{})
uniqueArray = make([]string, 0, len(a.array))
)
for i := 0; i < len(a.array); i++ {
temp = a.array[i]
if _, ok = uniqueSet[temp]; ok {
continue
}
uniqueSet[temp] = struct{}{}
uniqueArray = append(uniqueArray, temp)
}
a.array = uniqueArray
return a
}
@ -724,6 +733,9 @@ func (a *StrArray) IteratorDesc(f func(k int, v string) bool) {
// String returns current array as a string, which implements like json.Marshal does.
func (a *StrArray) String() string {
if a == nil {
return ""
}
a.mu.RLock()
defer a.mu.RUnlock()
buffer := bytes.NewBuffer(nil)

View File

@ -36,9 +36,9 @@ type SortedArray struct {
// NewSortedArray creates and returns an empty sorted array.
// The parameter `safe` is used to specify whether using array in concurrent-safety, which is false in default.
// The parameter `comparator` used to compare values to sort in array,
// if it returns value < 0, means v1 < v2; the v1 will be inserted before v2;
// if it returns value = 0, means v1 = v2; the v1 will be replaced by v2;
// if it returns value > 0, means v1 > v2; the v1 will be inserted after v2;
// if it returns value < 0, means `a` < `b`; the `a` will be inserted before `b`;
// if it returns value = 0, means `a` = `b`; the `a` will be replaced by `b`;
// if it returns value > 0, means `a` > `b`; the `a` will be inserted after `b`;
func NewSortedArray(comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
return NewSortedArraySize(0, comparator, safe...)
}
@ -653,6 +653,9 @@ func (a *SortedArray) IteratorDesc(f func(k int, v interface{}) bool) {
// String returns current array as a string, which implements like json.Marshal does.
func (a *SortedArray) String() string {
if a == nil {
return ""
}
a.mu.RLock()
defer a.mu.RUnlock()
buffer := bytes.NewBuffer(nil)

View File

@ -646,6 +646,9 @@ func (a *SortedIntArray) IteratorDesc(f func(k int, v int) bool) {
// String returns current array as a string, which implements like json.Marshal does.
func (a *SortedIntArray) String() string {
if a == nil {
return ""
}
return "[" + a.Join(",") + "]"
}

View File

@ -648,6 +648,9 @@ func (a *SortedStrArray) IteratorDesc(f func(k int, v string) bool) {
// String returns current array as a string, which implements like json.Marshal does.
func (a *SortedStrArray) String() string {
if a == nil {
return ""
}
a.mu.RLock()
defer a.mu.RUnlock()
buffer := bytes.NewBuffer(nil)

View File

@ -576,7 +576,7 @@ func TestArray_Json(t *testing.T) {
var a3 garray.Array
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
})
// value.
@ -595,7 +595,7 @@ func TestArray_Json(t *testing.T) {
var a3 garray.Array
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
})
// pointer
@ -609,11 +609,11 @@ func TestArray_Json(t *testing.T) {
"Scores": []int{99, 100, 98},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, data["Scores"])
})
@ -628,11 +628,11 @@ func TestArray_Json(t *testing.T) {
"Scores": []int{99, 100, 98},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, data["Scores"])
})
@ -720,7 +720,7 @@ func TestArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": g.Slice{1, 2, 3},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
})

View File

@ -619,7 +619,7 @@ func TestIntArray_Json(t *testing.T) {
var a3 garray.IntArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
})
// array value
@ -637,7 +637,7 @@ func TestIntArray_Json(t *testing.T) {
var a3 garray.IntArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
})
// array pointer
@ -651,11 +651,11 @@ func TestIntArray_Json(t *testing.T) {
"Scores": []int{99, 100, 98},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, data["Scores"])
})
@ -670,11 +670,11 @@ func TestIntArray_Json(t *testing.T) {
"Scores": []int{99, 100, 98},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, data["Scores"])
})
@ -752,7 +752,7 @@ func TestIntArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": []byte(`[1,2,3]`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
})
@ -763,7 +763,7 @@ func TestIntArray_UnmarshalValue(t *testing.T) {
// "name": "john",
// "array": g.Slice{1, 2, 3},
// }, &v)
// t.Assert(err, nil)
// t.AssertNil(err)
// t.Assert(v.Name, "john")
// t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
// })

View File

@ -619,7 +619,7 @@ func TestStrArray_Json(t *testing.T) {
var a3 garray.StrArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
})
// array value
@ -637,7 +637,7 @@ func TestStrArray_Json(t *testing.T) {
var a3 garray.StrArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
})
// array pointer
@ -651,11 +651,11 @@ func TestStrArray_Json(t *testing.T) {
"Scores": []string{"A+", "A", "A"},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, data["Scores"])
})
@ -670,11 +670,11 @@ func TestStrArray_Json(t *testing.T) {
"Scores": []string{"A+", "A", "A"},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, data["Scores"])
})
@ -751,7 +751,7 @@ func TestStrArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": []byte(`["1","2","3"]`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.SliceStr{"1", "2", "3"})
})
@ -762,7 +762,7 @@ func TestStrArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": g.SliceStr{"1", "2", "3"},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.SliceStr{"1", "2", "3"})
})

View File

@ -661,7 +661,7 @@ func TestSortedArray_Json(t *testing.T) {
var a3 garray.SortedArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
t.Assert(a3.Interfaces(), s1)
})
@ -681,7 +681,7 @@ func TestSortedArray_Json(t *testing.T) {
var a3 garray.SortedArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
t.Assert(a3.Interfaces(), s1)
})
@ -696,11 +696,11 @@ func TestSortedArray_Json(t *testing.T) {
"Scores": []int{99, 100, 98},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.AssertNE(user.Scores, nil)
t.Assert(user.Scores.Len(), 3)
@ -732,11 +732,11 @@ func TestSortedArray_Json(t *testing.T) {
"Scores": []int{99, 100, 98},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.AssertNE(user.Scores, nil)
t.Assert(user.Scores.Len(), 3)
@ -830,7 +830,7 @@ func TestSortedArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": []byte(`[2,3,1]`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
})
@ -841,7 +841,7 @@ func TestSortedArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": g.Slice{2, 3, 1},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
})

View File

@ -561,7 +561,7 @@ func TestSortedIntArray_Json(t *testing.T) {
var a3 garray.SortedIntArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
})
// array value
@ -580,7 +580,7 @@ func TestSortedIntArray_Json(t *testing.T) {
var a3 garray.SortedIntArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
})
// array pointer
@ -594,11 +594,11 @@ func TestSortedIntArray_Json(t *testing.T) {
"Scores": []int{99, 100, 98},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, []int{98, 99, 100})
})
@ -613,11 +613,11 @@ func TestSortedIntArray_Json(t *testing.T) {
"Scores": []int{99, 100, 98},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, []int{98, 99, 100})
})
@ -695,7 +695,7 @@ func TestSortedIntArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": []byte(`[2,3,1]`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
})
@ -706,7 +706,7 @@ func TestSortedIntArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": g.Slice{2, 3, 1},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
})

View File

@ -583,7 +583,7 @@ func TestSortedStrArray_Json(t *testing.T) {
var a3 garray.SortedStrArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
t.Assert(a3.Interfaces(), s1)
})
@ -604,7 +604,7 @@ func TestSortedStrArray_Json(t *testing.T) {
var a3 garray.SortedStrArray
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Slice(), s1)
t.Assert(a3.Interfaces(), s1)
})
@ -619,11 +619,11 @@ func TestSortedStrArray_Json(t *testing.T) {
"Scores": []string{"A+", "A", "A"},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, []string{"A", "A", "A+"})
})
@ -638,11 +638,11 @@ func TestSortedStrArray_Json(t *testing.T) {
"Scores": []string{"A+", "A", "A"},
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
user := new(User)
err = json.UnmarshalUseNumber(b, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Name, data["Name"])
t.Assert(user.Scores, []string{"A", "A", "A+"})
})
@ -719,7 +719,7 @@ func TestSortedStrArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": []byte(`["1","3","2"]`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.SliceStr{"1", "2", "3"})
})
@ -730,7 +730,7 @@ func TestSortedStrArray_UnmarshalValue(t *testing.T) {
"name": "john",
"array": g.SliceStr{"1", "3", "2"},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Array.Slice(), g.SliceStr{"1", "2", "3"})
})

View File

@ -503,6 +503,9 @@ func (l *List) Join(glue string) string {
// String returns current list as a string.
func (l *List) String() string {
if l == nil {
return ""
}
return "[" + l.Join(",") + "]"
}

View File

@ -709,20 +709,20 @@ func TestList_Json(t *testing.T) {
a := []interface{}{"a", "b", "c"}
l := New()
b, err := json.Marshal(a)
t.Assert(err, nil)
t.AssertNil(err)
err = json.UnmarshalUseNumber(b, l)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(l.FrontAll(), a)
})
gtest.C(t, func(t *gtest.T) {
var l List
a := []interface{}{"a", "b", "c"}
b, err := json.Marshal(a)
t.Assert(err, nil)
t.AssertNil(err)
err = json.UnmarshalUseNumber(b, &l)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(l.FrontAll(), a)
})
}
@ -739,7 +739,7 @@ func TestList_UnmarshalValue(t *testing.T) {
"name": "john",
"list": []byte(`[1,2,3]`),
}, &tlist)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(tlist.Name, "john")
t.Assert(tlist.List.FrontAll(), []interface{}{1, 2, 3})
})
@ -750,7 +750,7 @@ func TestList_UnmarshalValue(t *testing.T) {
"name": "john",
"list": []interface{}{1, 2, 3},
}, &tlist)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(tlist.Name, "john")
t.Assert(tlist.List.FrontAll(), []interface{}{1, 2, 3})
})

View File

@ -456,6 +456,9 @@ func (m *AnyAnyMap) Merge(other *AnyAnyMap) {
// String returns the map as a string.
func (m *AnyAnyMap) String() string {
if m == nil {
return ""
}
b, _ := m.MarshalJSON()
return string(b)
}

View File

@ -455,6 +455,9 @@ func (m *IntAnyMap) Merge(other *IntAnyMap) {
// String returns the map as a string.
func (m *IntAnyMap) String() string {
if m == nil {
return ""
}
b, _ := m.MarshalJSON()
return string(b)
}

View File

@ -426,6 +426,9 @@ func (m *IntIntMap) Merge(other *IntIntMap) {
// String returns the map as a string.
func (m *IntIntMap) String() string {
if m == nil {
return ""
}
b, _ := m.MarshalJSON()
return string(b)
}

View File

@ -426,6 +426,9 @@ func (m *IntStrMap) Merge(other *IntStrMap) {
// String returns the map as a string.
func (m *IntStrMap) String() string {
if m == nil {
return ""
}
b, _ := m.MarshalJSON()
return string(b)
}

View File

@ -451,6 +451,9 @@ func (m *StrAnyMap) Merge(other *StrAnyMap) {
// String returns the map as a string.
func (m *StrAnyMap) String() string {
if m == nil {
return ""
}
b, _ := m.MarshalJSON()
return string(b)
}

View File

@ -430,6 +430,9 @@ func (m *StrIntMap) Merge(other *StrIntMap) {
// String returns the map as a string.
func (m *StrIntMap) String() string {
if m == nil {
return ""
}
b, _ := m.MarshalJSON()
return string(b)
}

View File

@ -429,6 +429,9 @@ func (m *StrStrMap) Merge(other *StrStrMap) {
// String returns the map as a string.
func (m *StrStrMap) String() string {
if m == nil {
return ""
}
b, _ := m.MarshalJSON()
return string(b)
}

View File

@ -7,6 +7,9 @@
package gmap
import (
"bytes"
"fmt"
"github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/empty"
@ -15,6 +18,13 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)
// ListMap is a map that preserves insertion-order.
//
// It is backed by a hash table to store values and doubly-linked list to store ordering.
//
// Structure is not thread safe.
//
// Reference: http://en.wikipedia.org/wiki/Associative_array
type ListMap struct {
mu rwmutex.RWMutex
data map[interface{}]*glist.Element
@ -58,7 +68,7 @@ func (m *ListMap) IteratorAsc(f func(key interface{}, value interface{}) bool) {
m.mu.RLock()
defer m.mu.RUnlock()
if m.list != nil {
node := (*gListMapNode)(nil)
var node *gListMapNode
m.list.IteratorAsc(func(e *glist.Element) bool {
node = e.Value.(*gListMapNode)
return f(node.key, node.value)
@ -72,7 +82,7 @@ func (m *ListMap) IteratorDesc(f func(key interface{}, value interface{}) bool)
m.mu.RLock()
defer m.mu.RUnlock()
if m.list != nil {
node := (*gListMapNode)(nil)
var node *gListMapNode
m.list.IteratorDesc(func(e *glist.Element) bool {
node = e.Value.(*gListMapNode)
return f(node.key, node.value)
@ -146,8 +156,10 @@ func (m *ListMap) MapStrAny() map[string]interface{} {
func (m *ListMap) FilterEmpty() {
m.mu.Lock()
if m.list != nil {
keys := make([]interface{}, 0)
node := (*gListMapNode)(nil)
var (
keys = make([]interface{}, 0)
node *gListMapNode
)
m.list.IteratorAsc(func(e *glist.Element) bool {
node = e.Value.(*gListMapNode)
if empty.IsEmpty(node.value) {
@ -495,7 +507,7 @@ func (m *ListMap) Merge(other *ListMap) {
other.mu.RLock()
defer other.mu.RUnlock()
}
node := (*gListMapNode)(nil)
var node *gListMapNode
other.list.IteratorAsc(func(e *glist.Element) bool {
node = e.Value.(*gListMapNode)
if e, ok := m.data[node.key]; !ok {
@ -509,13 +521,34 @@ func (m *ListMap) Merge(other *ListMap) {
// String returns the map as a string.
func (m *ListMap) String() string {
if m == nil {
return ""
}
b, _ := m.MarshalJSON()
return string(b)
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (m ListMap) MarshalJSON() ([]byte, error) {
return json.Marshal(gconv.Map(m.Map()))
func (m ListMap) MarshalJSON() (jsonBytes []byte, err error) {
if m.data == nil {
return []byte("null"), nil
}
buffer := bytes.NewBuffer(nil)
buffer.WriteByte('{')
m.Iterator(func(key, value interface{}) bool {
valueBytes, valueJsonErr := json.Marshal(value)
if valueJsonErr != nil {
err = valueJsonErr
return false
}
if buffer.Len() > 1 {
buffer.WriteByte(',')
}
buffer.WriteString(fmt.Sprintf(`"%v":%s`, key, valueBytes))
return true
})
buffer.WriteByte('}')
return buffer.Bytes(), nil
}
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.

View File

@ -8,6 +8,7 @@ package gmap_test
import (
"fmt"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
@ -195,7 +196,7 @@ func ExampleListMap_Sets() {
m.Sets(addMap)
fmt.Println(m)
// Output:
// May Output:
// {"key1":"val1","key2":"val2","key3":"val3"}
}
@ -562,12 +563,10 @@ func ExampleListMap_String() {
func ExampleListMap_MarshalJSON() {
var m gmap.ListMap
m.Sets(g.MapAnyAny{
"k1": "v1",
"k2": "v2",
"k3": "v3",
"k4": "v4",
})
m.Set("k1", "v1")
m.Set("k2", "v2")
m.Set("k3", "v3")
m.Set("k4", "v4")
bytes, err := json.Marshal(&m)
if err == nil {

View File

@ -8,6 +8,7 @@ package gmap_test
import (
"fmt"
"github.com/gogf/gf/v2/util/gutil"
"github.com/gogf/gf/v2/container/gmap"
@ -277,7 +278,7 @@ func ExampleNewListMapFrom() {
n := gmap.NewListMapFrom(m.Map(), true)
fmt.Println(n)
// Output:
// May Output:
// {"key1":"var1","key2":"var2"}
// {"key1":"var1","key2":"var2"}
}
@ -290,7 +291,7 @@ func ExampleNewTreeMap() {
fmt.Println(m.Map())
// Output:
// May Output:
// map[key1:var1 key2:var2]
}
@ -305,7 +306,7 @@ func ExampleNewTreeMapFrom() {
n := gmap.NewListMapFrom(m.Map(), true)
fmt.Println(n.Map())
// Output:
// May Output:
// map[key1:var1 key2:var2]
// map[key1:var1 key2:var2]
}

View File

@ -253,11 +253,11 @@ func Test_AnyAnyMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(gconv.Map(data))
t.Assert(err, nil)
t.AssertNil(err)
m := gmap.New()
err = json.UnmarshalUseNumber(b, m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -267,11 +267,11 @@ func Test_AnyAnyMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(gconv.Map(data))
t.Assert(err, nil)
t.AssertNil(err)
var m gmap.Map
err = json.UnmarshalUseNumber(b, &m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -342,7 +342,7 @@ func TestAnyAnyMap_UnmarshalValue(t *testing.T) {
"name": "john",
"map": []byte(`{"k1":"v1","k2":"v2"}`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), "v1")
@ -358,7 +358,7 @@ func TestAnyAnyMap_UnmarshalValue(t *testing.T) {
"k2": "v2",
},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), "v1")

View File

@ -242,11 +242,11 @@ func Test_IntAnyMap_Json(t *testing.T) {
2: "v2",
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
m := gmap.NewIntAnyMap()
err = json.UnmarshalUseNumber(b, m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get(1), data[1])
t.Assert(m.Get(2), data[2])
})
@ -317,7 +317,7 @@ func TestIntAnyMap_UnmarshalValue(t *testing.T) {
"name": "john",
"map": []byte(`{"1":"v1","2":"v2"}`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get(1), "v1")
@ -333,7 +333,7 @@ func TestIntAnyMap_UnmarshalValue(t *testing.T) {
2: "v2",
},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get(1), "v1")

View File

@ -248,11 +248,11 @@ func Test_IntIntMap_Json(t *testing.T) {
2: 20,
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
m := gmap.NewIntIntMap()
err = json.UnmarshalUseNumber(b, m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get(1), data[1])
t.Assert(m.Get(2), data[2])
})
@ -323,7 +323,7 @@ func TestIntIntMap_UnmarshalValue(t *testing.T) {
"name": "john",
"map": []byte(`{"1":1,"2":2}`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get(1), "1")
@ -339,7 +339,7 @@ func TestIntIntMap_UnmarshalValue(t *testing.T) {
2: 2,
},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get(1), "1")

View File

@ -246,11 +246,11 @@ func Test_IntStrMap_Json(t *testing.T) {
2: "v2",
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
m := gmap.NewIntStrMap()
err = json.UnmarshalUseNumber(b, m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get(1), data[1])
t.Assert(m.Get(2), data[2])
})
@ -321,7 +321,7 @@ func TestIntStrMap_UnmarshalValue(t *testing.T) {
"name": "john",
"map": []byte(`{"1":"v1","2":"v2"}`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get(1), "v1")
@ -337,7 +337,7 @@ func TestIntStrMap_UnmarshalValue(t *testing.T) {
2: "v2",
},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get(1), "v1")

View File

@ -240,11 +240,11 @@ func Test_StrAnyMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
m := gmap.NewStrAnyMap()
err = json.UnmarshalUseNumber(b, m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -254,11 +254,11 @@ func Test_StrAnyMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
var m gmap.StrAnyMap
err = json.UnmarshalUseNumber(b, &m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -329,7 +329,7 @@ func TestStrAnyMap_UnmarshalValue(t *testing.T) {
"name": "john",
"map": []byte(`{"k1":"v1","k2":"v2"}`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), "v1")
@ -345,7 +345,7 @@ func TestStrAnyMap_UnmarshalValue(t *testing.T) {
"k2": "v2",
},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), "v1")

View File

@ -244,11 +244,11 @@ func Test_StrIntMap_Json(t *testing.T) {
"k2": 2,
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
m := gmap.NewStrIntMap()
err = json.UnmarshalUseNumber(b, m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -258,11 +258,11 @@ func Test_StrIntMap_Json(t *testing.T) {
"k2": 2,
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
var m gmap.StrIntMap
err = json.UnmarshalUseNumber(b, &m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -333,7 +333,7 @@ func TestStrIntMap_UnmarshalValue(t *testing.T) {
"name": "john",
"map": []byte(`{"k1":1,"k2":2}`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), 1)
@ -349,7 +349,7 @@ func TestStrIntMap_UnmarshalValue(t *testing.T) {
"k2": 2,
},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), 1)

View File

@ -241,11 +241,11 @@ func Test_StrStrMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
m := gmap.NewStrStrMap()
err = json.UnmarshalUseNumber(b, m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -255,11 +255,11 @@ func Test_StrStrMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(data)
t.Assert(err, nil)
t.AssertNil(err)
var m gmap.StrStrMap
err = json.UnmarshalUseNumber(b, &m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -330,7 +330,7 @@ func TestStrStrMap_UnmarshalValue(t *testing.T) {
"name": "john",
"map": []byte(`{"k1":"v1","k2":"v2"}`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), "v1")
@ -346,7 +346,7 @@ func TestStrStrMap_UnmarshalValue(t *testing.T) {
"k2": "v2",
},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), "v1")

View File

@ -186,12 +186,12 @@ func Test_ListMap_Json(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
data := g.MapAnyAny{
"k1": "v1",
"k2": "v2",
}
m1 := gmap.NewListMapFrom(data)
b1, err1 := json.Marshal(m1)
t.AssertNil(err1)
b2, err2 := json.Marshal(gconv.Map(data))
t.Assert(err1, err2)
t.AssertNil(err2)
t.Assert(b1, b2)
})
// Unmarshal
@ -201,11 +201,11 @@ func Test_ListMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(gconv.Map(data))
t.Assert(err, nil)
t.AssertNil(err)
m := gmap.NewListMap()
err = json.UnmarshalUseNumber(b, m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -216,16 +216,37 @@ func Test_ListMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(gconv.Map(data))
t.Assert(err, nil)
t.AssertNil(err)
var m gmap.ListMap
err = json.UnmarshalUseNumber(b, &m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
}
func Test_ListMap_Json_Sequence(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewListMap()
for i := 'z'; i >= 'a'; i-- {
m.Set(string(i), i)
}
b, err := json.Marshal(m)
t.AssertNil(err)
t.Assert(b, `{"z":122,"y":121,"x":120,"w":119,"v":118,"u":117,"t":116,"s":115,"r":114,"q":113,"p":112,"o":111,"n":110,"m":109,"l":108,"k":107,"j":106,"i":105,"h":104,"g":103,"f":102,"e":101,"d":100,"c":99,"b":98,"a":97}`)
})
gtest.C(t, func(t *gtest.T) {
m := gmap.NewListMap()
for i := 'a'; i <= 'z'; i++ {
m.Set(string(i), i)
}
b, err := json.Marshal(m)
t.AssertNil(err)
t.Assert(b, `{"a":97,"b":98,"c":99,"d":100,"e":101,"f":102,"g":103,"h":104,"i":105,"j":106,"k":107,"l":108,"m":109,"n":110,"o":111,"p":112,"q":113,"r":114,"s":115,"t":116,"u":117,"v":118,"w":119,"x":120,"y":121,"z":122}`)
})
}
func Test_ListMap_Pop(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewListMapFrom(g.MapAnyAny{
@ -291,7 +312,7 @@ func TestListMap_UnmarshalValue(t *testing.T) {
"name": "john",
"map": []byte(`{"1":"v1","2":"v2"}`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("1"), "v1")
@ -307,7 +328,7 @@ func TestListMap_UnmarshalValue(t *testing.T) {
2: "v2",
},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("1"), "v1")

View File

@ -185,11 +185,11 @@ func Test_TreeMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(gconv.Map(data))
t.Assert(err, nil)
t.AssertNil(err)
m := gmap.NewTreeMap(gutil.ComparatorString)
err = json.UnmarshalUseNumber(b, m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -199,11 +199,11 @@ func Test_TreeMap_Json(t *testing.T) {
"k2": "v2",
}
b, err := json.Marshal(gconv.Map(data))
t.Assert(err, nil)
t.AssertNil(err)
var m gmap.TreeMap
err = json.UnmarshalUseNumber(b, &m)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(m.Get("k1"), data["k1"])
t.Assert(m.Get("k2"), data["k2"])
})
@ -221,7 +221,7 @@ func TestTreeMap_UnmarshalValue(t *testing.T) {
"name": "john",
"map": []byte(`{"k1":"v1","k2":"v2"}`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), "v1")
@ -237,7 +237,7 @@ func TestTreeMap_UnmarshalValue(t *testing.T) {
"k2": "v2",
},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Map.Size(), 2)
t.Assert(v.Map.Get("k1"), "v1")

View File

@ -109,7 +109,7 @@ func (p *Pool) Get() (interface{}, error) {
if f.expireAt == 0 || f.expireAt > gtime.TimestampMilli() {
return f.value, nil
} else if p.ExpireFunc != nil {
// TODO: move expire function calling asynchronously from `Get` operation.
// TODO: move expire function calling asynchronously out from `Get` operation.
p.ExpireFunc(f.value)
}
} else {
@ -129,7 +129,7 @@ func (p *Pool) Size() int {
// Close closes the pool. If `p` has ExpireFunc,
// then it automatically closes all items using this function before it's closed.
// Commonly you do not need call this function manually.
// Commonly you do not need to call this function manually.
func (p *Pool) Close() {
p.closed.Set(true)
}

View File

@ -223,6 +223,9 @@ func (set *Set) Join(glue string) string {
// String returns items as a string, which implements like json.Marshal does.
func (set *Set) String() string {
if set == nil {
return ""
}
set.mu.RLock()
defer set.mu.RUnlock()
var (

View File

@ -204,6 +204,9 @@ func (set *IntSet) Join(glue string) string {
// String returns items as a string, which implements like json.Marshal does.
func (set *IntSet) String() string {
if set == nil {
return ""
}
return "[" + set.Join(",") + "]"
}

View File

@ -218,6 +218,9 @@ func (set *StrSet) Join(glue string) string {
// String returns items as a string, which implements like json.Marshal does.
func (set *StrSet) String() string {
if set == nil {
return ""
}
set.mu.RLock()
defer set.mu.RUnlock()
var (

View File

@ -336,7 +336,7 @@ func TestSet_Json(t *testing.T) {
var a3 gset.Set
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Contains("a"), true)
t.Assert(a3.Contains("b"), true)
t.Assert(a3.Contains("c"), true)
@ -438,7 +438,7 @@ func TestSet_UnmarshalValue(t *testing.T) {
"name": "john",
"set": []byte(`["k1","k2","k3"]`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Set.Size(), 3)
t.Assert(v.Set.Contains("k1"), true)
@ -453,7 +453,7 @@ func TestSet_UnmarshalValue(t *testing.T) {
"name": "john",
"set": g.Slice{"k1", "k2", "k3"},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Set.Size(), 3)
t.Assert(v.Set.Contains("k1"), true)

View File

@ -368,7 +368,7 @@ func TestIntSet_Json(t *testing.T) {
var a3 gset.IntSet
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a2.Contains(1), true)
t.Assert(a2.Contains(2), true)
t.Assert(a2.Contains(3), true)
@ -402,7 +402,7 @@ func TestIntSet_UnmarshalValue(t *testing.T) {
"name": "john",
"set": []byte(`[1,2,3]`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Set.Size(), 3)
t.Assert(v.Set.Contains(1), true)
@ -417,7 +417,7 @@ func TestIntSet_UnmarshalValue(t *testing.T) {
"name": "john",
"set": g.Slice{1, 2, 3},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Set.Size(), 3)
t.Assert(v.Set.Contains(1), true)

View File

@ -414,7 +414,7 @@ func TestStrSet_Json(t *testing.T) {
var a3 gset.StrSet
err := json.UnmarshalUseNumber(b2, &a3)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(a3.Contains("a"), true)
t.Assert(a3.Contains("b"), true)
t.Assert(a3.Contains("c"), true)
@ -453,7 +453,7 @@ func TestStrSet_UnmarshalValue(t *testing.T) {
"name": "john",
"set": []byte(`["1","2","3"]`),
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Set.Size(), 3)
t.Assert(v.Set.Contains("1"), true)
@ -468,7 +468,7 @@ func TestStrSet_UnmarshalValue(t *testing.T) {
"name": "john",
"set": g.SliceStr{"1", "2", "3"},
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Set.Size(), 3)
t.Assert(v.Set.Contains("1"), true)

View File

@ -7,6 +7,7 @@
package gtree
import (
"bytes"
"fmt"
"github.com/gogf/gf/v2/container/gvar"
@ -398,6 +399,9 @@ func (tree *AVLTree) Replace(data map[interface{}]interface{}) {
// String returns a string representation of container
func (tree *AVLTree) String() string {
if tree == nil {
return ""
}
tree.mu.RLock()
defer tree.mu.RUnlock()
str := ""
@ -780,8 +784,26 @@ func output(node *AVLTreeNode, prefix string, isTail bool, str *string) {
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (tree AVLTree) MarshalJSON() ([]byte, error) {
return json.Marshal(tree.MapStrAny())
func (tree AVLTree) MarshalJSON() (jsonBytes []byte, err error) {
if tree.root == nil {
return []byte("null"), nil
}
buffer := bytes.NewBuffer(nil)
buffer.WriteByte('{')
tree.Iterator(func(key, value interface{}) bool {
valueBytes, valueJsonErr := json.Marshal(value)
if valueJsonErr != nil {
err = valueJsonErr
return false
}
if buffer.Len() > 1 {
buffer.WriteByte(',')
}
buffer.WriteString(fmt.Sprintf(`"%v":%s`, key, valueBytes))
return true
})
buffer.WriteByte('}')
return buffer.Bytes(), nil
}
// getComparator returns the comparator if it's previously set,

View File

@ -367,6 +367,9 @@ func (tree *BTree) Right() *BTreeEntry {
// String returns a string representation of container (for debugging purposes)
func (tree *BTree) String() string {
if tree == nil {
return ""
}
tree.mu.RLock()
defer tree.mu.RUnlock()
var buffer bytes.Buffer
@ -944,8 +947,26 @@ func (tree *BTree) deleteChild(node *BTreeNode, index int) {
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (tree BTree) MarshalJSON() ([]byte, error) {
return json.Marshal(tree.MapStrAny())
func (tree BTree) MarshalJSON() (jsonBytes []byte, err error) {
if tree.root == nil {
return []byte("null"), nil
}
buffer := bytes.NewBuffer(nil)
buffer.WriteByte('{')
tree.Iterator(func(key, value interface{}) bool {
valueBytes, valueJsonErr := json.Marshal(value)
if valueJsonErr != nil {
err = valueJsonErr
return false
}
if buffer.Len() > 1 {
buffer.WriteByte(',')
}
buffer.WriteString(fmt.Sprintf(`"%v":%s`, key, valueBytes))
return true
})
buffer.WriteByte('}')
return buffer.Bytes(), nil
}
// getComparator returns the comparator if it's previously set,

View File

@ -7,6 +7,7 @@
package gtree
import (
"bytes"
"fmt"
"github.com/gogf/gf/v2/container/gvar"
@ -622,6 +623,9 @@ func (tree *RedBlackTree) Replace(data map[interface{}]interface{}) {
// String returns a string representation of container.
func (tree *RedBlackTree) String() string {
if tree == nil {
return ""
}
tree.mu.RLock()
defer tree.mu.RUnlock()
str := ""
@ -925,8 +929,26 @@ func (tree *RedBlackTree) nodeColor(node *RedBlackTreeNode) color {
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (tree RedBlackTree) MarshalJSON() ([]byte, error) {
return json.Marshal(gconv.Map(tree.Map()))
func (tree RedBlackTree) MarshalJSON() (jsonBytes []byte, err error) {
if tree.root == nil {
return []byte("null"), nil
}
buffer := bytes.NewBuffer(nil)
buffer.WriteByte('{')
tree.Iterator(func(key, value interface{}) bool {
valueBytes, valueJsonErr := json.Marshal(value)
if valueJsonErr != nil {
err = valueJsonErr
return false
}
if buffer.Len() > 1 {
buffer.WriteByte(',')
}
buffer.WriteString(fmt.Sprintf(`"%v":%s`, key, valueBytes))
return true
})
buffer.WriteByte('}')
return buffer.Bytes(), nil
}
// UnmarshalJSON implements the interface UnmarshalJSON for json.Unmarshal.

View File

@ -56,16 +56,16 @@ func Test_Bool_JSON(t *testing.T) {
var err error
i := gtype.NewBool()
err = json.UnmarshalUseNumber([]byte("true"), &i)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i.Val(), true)
err = json.UnmarshalUseNumber([]byte("false"), &i)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i.Val(), false)
err = json.UnmarshalUseNumber([]byte("1"), &i)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i.Val(), true)
err = json.UnmarshalUseNumber([]byte("0"), &i)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i.Val(), false)
})
@ -79,7 +79,7 @@ func Test_Bool_JSON(t *testing.T) {
i2 := gtype.NewBool()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), i.Val())
})
gtest.C(t, func(t *gtest.T) {
@ -92,7 +92,7 @@ func Test_Bool_JSON(t *testing.T) {
i2 := gtype.NewBool()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), i.Val())
})
}
@ -108,7 +108,7 @@ func Test_Bool_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "true",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), true)
})
@ -118,7 +118,7 @@ func Test_Bool_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "false",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), false)
})

View File

@ -54,7 +54,7 @@ func Test_Byte_JSON(t *testing.T) {
var err error
i := gtype.NewByte()
err = json.UnmarshalUseNumber([]byte("49"), &i)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i.Val(), "49")
})
}
@ -70,7 +70,7 @@ func Test_Byte_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "2",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "2")
})

View File

@ -40,7 +40,7 @@ func Test_Bytes_JSON(t *testing.T) {
i2 := gtype.NewBytes()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), b)
})
}
@ -56,7 +56,7 @@ func Test_Bytes_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123")
})

View File

@ -42,7 +42,7 @@ func Test_Float32_JSON(t *testing.T) {
i2 := gtype.NewFloat32()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), v)
})
}
@ -58,7 +58,7 @@ func Test_Float32_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123.456",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123.456")
})

View File

@ -40,7 +40,7 @@ func Test_Float64_JSON(t *testing.T) {
i2 := gtype.NewFloat64()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), v)
})
}
@ -56,7 +56,7 @@ func Test_Float64_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123.456",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123.456")
})

View File

@ -53,7 +53,7 @@ func Test_Int32_JSON(t *testing.T) {
i2 := gtype.NewInt32()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), v)
})
}
@ -69,7 +69,7 @@ func Test_Int32_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123")
})

View File

@ -52,7 +52,7 @@ func Test_Int64_JSON(t *testing.T) {
i2 := gtype.NewInt64()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), i)
})
}
@ -68,7 +68,7 @@ func Test_Int64_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123")
})

View File

@ -52,7 +52,7 @@ func Test_Int_JSON(t *testing.T) {
i2 := gtype.NewInt()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), v)
})
}
@ -68,7 +68,7 @@ func Test_Int_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123")
})

View File

@ -42,7 +42,7 @@ func Test_Interface_JSON(t *testing.T) {
i2 := gtype.New()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), s)
})
}
@ -58,7 +58,7 @@ func Test_Interface_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123")
})

View File

@ -40,7 +40,7 @@ func Test_String_JSON(t *testing.T) {
i2 := gtype.NewString()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), s)
})
}
@ -56,7 +56,7 @@ func Test_String_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123")
})

View File

@ -52,7 +52,7 @@ func Test_Uint32_JSON(t *testing.T) {
i2 := gtype.NewUint32()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), i)
})
}
@ -68,7 +68,7 @@ func Test_Uint32_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123")
})

View File

@ -56,7 +56,7 @@ func Test_Uint64_JSON(t *testing.T) {
i2 := gtype.NewUint64()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), i)
})
}
@ -72,7 +72,7 @@ func Test_Uint64_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123")
})

View File

@ -51,7 +51,7 @@ func Test_Uint_JSON(t *testing.T) {
i2 := gtype.NewUint()
err := json.UnmarshalUseNumber(b2, &i2)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(i2.Val(), i)
})
}
@ -67,7 +67,7 @@ func Test_Uint_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "123",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.Val(), "123")
})

View File

@ -18,10 +18,10 @@ import (
// New
func ExampleVarNew() {
v := gvar.New(400)
g.Dump(v)
fmt.Println(v)
// Output:
// "400"
// 400
}
// Clone

View File

@ -253,7 +253,7 @@ func Test_UnmarshalJson(t *testing.T) {
"name": "john",
"var": "v",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.String(), "v")
})
@ -267,7 +267,7 @@ func Test_UnmarshalJson(t *testing.T) {
"name": "john",
"var": "v",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.String(), "v")
})
@ -284,7 +284,7 @@ func Test_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "v",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.String(), "v")
})
@ -298,7 +298,7 @@ func Test_UnmarshalValue(t *testing.T) {
"name": "john",
"var": "v",
}, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.Name, "john")
t.Assert(v.Var.String(), "v")
})

View File

@ -40,10 +40,10 @@ func TestVar_Json(t *testing.T) {
s := "i love gf"
v := gvar.New(nil)
b, err := json.Marshal(s)
t.Assert(err, nil)
t.AssertNil(err)
err = json.UnmarshalUseNumber(b, v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.String(), s)
})
@ -51,10 +51,10 @@ func TestVar_Json(t *testing.T) {
var v gvar.Var
s := "i love gf"
b, err := json.Marshal(s)
t.Assert(err, nil)
t.AssertNil(err)
err = json.UnmarshalUseNumber(b, &v)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(v.String(), s)
})
}

View File

@ -55,7 +55,7 @@ func TestVar_Var_Attribute_Struct(t *testing.T) {
"uid": gvar.New(1),
"name": gvar.New("john"),
}, user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Uid, 1)
t.Assert(user.Name, "john")
})
@ -70,7 +70,7 @@ func TestVar_Var_Attribute_Struct(t *testing.T) {
"uid": gvar.New(1),
"name": gvar.New("john"),
}, &user)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(user.Uid, 1)
t.Assert(user.Name, "john")
})

View File

@ -14,9 +14,11 @@ import _ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
# Supported Drivers
## MySQL
## MySQL/MariaDB/TiDB
BuiltIn supported, nothing todo.
```
import _ "github.com/gogf/gf/contrib/drivers/mysql/v2"
```
## SQLite
```
@ -50,6 +52,15 @@ Note:
- It does not support `Save/Replace` features.
- It does not support `LastInsertId`.
## ClickHouse
```
import _ "github.com/gogf/gf/contrib/drivers/clickhouse/v2"
```
Note:
- It does not support `InsertIgnore/InsertGetId` features.
- It does not support `Transaction` feature.
- It does not support `RowsAffected` feature.
# Custom Drivers
It's quick and easy, please refer to current driver source.

View File

@ -8,5 +8,363 @@
package clickhouse
import (
_ "github.com/ClickHouse/clickhouse-go"
"context"
"database/sql"
"errors"
"fmt"
"github.com/ClickHouse/clickhouse-go/v2"
"github.com/longbridgeapp/sqlparser"
"net/url"
"strings"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
// Driver is the driver for postgresql database.
type Driver struct {
*gdb.Core
}
var (
// tableFieldsMap caches the table information retrieved from database.
tableFieldsMap = gmap.New(true)
errUnsupportedInsertIgnore = errors.New("unsupported method:InsertIgnore")
errUnsupportedInsertGetId = errors.New("unsupported method:InsertGetId")
errUnsupportedReplace = errors.New("unsupported method:Replace")
errUnsupportedBegin = errors.New("unsupported method:Begin")
errUnsupportedTransaction = errors.New("unsupported method:Transaction")
errNotCondition = errors.New("there should be WHERE condition statement for UPDATE/DELETE operation")
errNotAssignment = errors.New("there should be WHERE condition statement for Assignment operation")
)
func init() {
if err := gdb.Register(`clickhouse`, New()); err != nil {
panic(err)
}
}
// New create and returns a driver that implements gdb.Driver, which supports operations for clickhouse.
func New() gdb.Driver {
return &Driver{}
}
// New creates and returns a database object for clickhouse.
// It implements the interface of gdb.Driver for extra database driver installation.
func (d *Driver) New(core *gdb.Core, node *gdb.ConfigNode) (gdb.DB, error) {
return &Driver{
Core: core,
}, nil
}
// Open creates and returns an underlying sql.DB object for clickhouse.
func (d *Driver) Open(config *gdb.ConfigNode) (*sql.DB, error) {
var (
source string
driver = "clickhouse"
)
if config.Link != "" {
source = config.Link
} else if config.Pass != "" {
source = fmt.Sprintf(
"clickhouse://%s:%s@%s:%s/%s?charset=%s&debug=%t",
config.User, url.PathEscape(config.Pass), config.Host, config.Port, config.Name, config.Charset, config.Debug)
} else {
source = fmt.Sprintf(
"clickhouse://%s@%s:%s/%s?charset=%s&debug=%t",
config.User, config.Host, config.Port, config.Name, config.Charset, config.Debug)
}
db, err := sql.Open(driver, source)
if err != nil {
return nil, err
}
return db, nil
}
// Tables retrieves and returns the tables of current schema.
// It's mainly used in cli tool chain for automatically generating the models.
func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {
var result gdb.Result
link, err := d.SlaveLink(schema...)
if err != nil {
return nil, err
}
query := fmt.Sprintf("select name from `system`.tables where database = '%s'", d.GetConfig().Name)
result, err = d.DoSelect(ctx, link, query)
if err != nil {
return
}
for _, m := range result {
tables = append(tables, m["name"].String())
}
return
}
// TableFields retrieves and returns the fields' information of specified table of current schema.
// Also see DriverMysql.TableFields.
func (d *Driver) TableFields(
ctx context.Context, table string, schema ...string,
) (fields map[string]*gdb.TableField, err error) {
charL, charR := d.GetChars()
table = gstr.Trim(table, charL+charR)
if gstr.Contains(table, " ") {
return nil, gerror.NewCode(gcode.CodeInvalidParameter, "function TableFields supports only single table operations")
}
useSchema := d.GetSchema()
if len(schema) > 0 && schema[0] != "" {
useSchema = schema[0]
}
v := tableFieldsMap.GetOrSetFuncLock(
fmt.Sprintf(`clickhouse_table_fields_%s_%s@group:%s`, table, useSchema, d.GetGroup()),
func() interface{} {
var (
result gdb.Result
link gdb.Link
)
if link, err = d.SlaveLink(useSchema); err != nil {
return nil
}
getColumnsSql := fmt.Sprintf("select name,position,default_expression,comment,type from `system`.columns c where database = '%s' and `table` = '%s'", d.GetConfig().Name, table)
result, err = d.DoSelect(ctx, link, getColumnsSql)
if err != nil {
return nil
}
fields = make(map[string]*gdb.TableField)
for _, m := range result {
var (
isNull = false
fieldType = m["type"].String()
)
// in clickhouse , filed type like is Nullable(int)
fieldsResult, _ := gregex.MatchString(`^Nullable\((.*?)\)`, fieldType)
if len(fieldsResult) == 2 {
isNull = true
fieldType = fieldsResult[1]
}
fields[m["name"].String()] = &gdb.TableField{
Index: m["position"].Int(),
Name: m["name"].String(),
Default: m["default_expression"].Val(),
Comment: m["comment"].String(),
//Key: m["Key"].String(),
Type: fieldType,
Null: isNull,
}
}
return fields
},
)
if v != nil {
fields = v.(map[string]*gdb.TableField)
}
return
}
// FilteredLink retrieves and returns filtered `linkInfo` that can be using for
// logging or tracing purpose.
func (d *Driver) FilteredLink() string {
linkInfo := d.GetConfig().Link
if linkInfo == "" {
return ""
}
s, _ := gregex.ReplaceString(
`(.+?):(.+)@tcp(.+)`,
`$1:xxx@tcp$3`,
linkInfo,
)
return s
}
// PingMaster pings the master node to check authentication or keeps the connection alive.
func (d *Driver) PingMaster() error {
conn, err := d.Master()
if err != nil {
return err
}
return d.ping(conn)
}
// PingSlave pings the slave node to check authentication or keeps the connection alive.
func (d *Driver) PingSlave() error {
conn, err := d.Slave()
if err != nil {
return err
}
return d.ping(conn)
}
// ping Returns the Clickhouse specific error.
func (d *Driver) ping(conn *sql.DB) error {
err := conn.Ping()
if exception, ok := err.(*clickhouse.Exception); ok {
return errors.New(fmt.Sprintf("[%d]%s", exception.Code, exception.Message))
}
return err
}
// DoFilter handles the sql before posts it to database.
func (d *Driver) DoFilter(
ctx context.Context, link gdb.Link, originSql string, args []interface{},
) (newSql string, newArgs []interface{}, err error) {
if len(args) == 0 {
return originSql, args, nil
}
var index int
// Convert placeholder char '?' to string "$x".
originSql, _ = gregex.ReplaceStringFunc(`\?`, originSql, func(s string) string {
index++
return fmt.Sprintf(`$%d`, index)
})
// replace STD SQL to Clickhouse SQL grammar
parsedStmt, err := sqlparser.NewParser(strings.NewReader(originSql)).ParseStatement()
if err != nil {
return "", nil, err
}
switch stmt := parsedStmt.(type) {
case *sqlparser.UpdateStatement:
// MySQL eg: UPDATE visits SET xxx
// Clickhouse eg: ALTER TABLE visits UPDATE xxx
newSql, err = d.doFilterUpdate(stmt)
if err != nil {
return originSql, args, err
}
return newSql, args, nil
case *sqlparser.DeleteStatement:
// MySQL eg: DELETE FROM VISIT
// Clickhouse eg: ALTER TABLE VISIT DELETE WHERE filter_expr
newSql, err = d.doFilterDelete(stmt)
if err != nil {
return originSql, args, err
}
return newSql, args, nil
}
return originSql, args, nil
}
func (d *Driver) doFilterDelete(stmt *sqlparser.DeleteStatement) (string, error) {
if stmt.Condition == nil {
return "", errNotCondition
}
var (
condition = stmt.Condition.String()
tableName = stmt.TableName
)
newSql := fmt.Sprintf("ALTER TABLE %s DELETE WHERE %s", tableName, condition)
return newSql, nil
}
func (d *Driver) doFilterUpdate(stmt *sqlparser.UpdateStatement) (string, error) {
if stmt.Condition == nil {
return "", errNotCondition
}
if len(stmt.Assignments) == 0 {
return "", errNotAssignment
}
var (
condition = stmt.Condition.String()
assignment string
tableName = stmt.TableName
assignments = []string{}
)
for _, item := range stmt.Assignments {
assignments = append(assignments, item.String())
}
assignment = strings.Join(assignments, ",")
newSql := fmt.Sprintf("ALTER TABLE %s UPDATE %s WHERE %s", tableName, assignment, condition)
return newSql, nil
}
// DoCommit commits current sql and arguments to underlying sql driver.
func (d *Driver) DoCommit(ctx context.Context, in gdb.DoCommitInput) (out gdb.DoCommitOutput, err error) {
ctx = d.InjectIgnoreResult(ctx)
return d.Core.DoCommit(ctx, in)
}
func (d *Driver) DoInsert(
ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption,
) (result sql.Result, err error) {
var (
keys []string // Field names.
valueHolder = make([]string, 0)
)
// Handle the field names and placeholders.
for k := range list[0] {
keys = append(keys, k)
valueHolder = append(valueHolder, "?")
}
// Prepare the batch result pointer.
var (
charL, charR = d.Core.GetChars()
keysStr = charL + strings.Join(keys, charR+","+charL) + charR
holderStr = strings.Join(valueHolder, ",")
tx = &gdb.TX{}
stdSqlResult sql.Result
stmt *gdb.Stmt
)
tx, err = d.Core.Begin(ctx)
if err != nil {
return
}
stmt, err = tx.Prepare(fmt.Sprintf(
"INSERT INTO %s(%s) VALUES (%s)",
d.QuotePrefixTableName(table), keysStr,
holderStr,
))
if err != nil {
return
}
for i := 0; i < len(list); i++ {
params := make([]interface{}, 0) // Values that will be committed to underlying database driver.
for _, k := range keys {
params = append(params, list[i][k])
}
// Prepare is allowed to execute only once in a transaction opened by clickhouse
stdSqlResult, err = stmt.ExecContext(ctx, params...)
if err != nil {
return stdSqlResult, err
}
}
return stdSqlResult, tx.Commit()
}
// ConvertDataForRecord converting for any data that will be inserted into table/collection as a record.
func (d *Driver) ConvertDataForRecord(ctx context.Context, value interface{}) map[string]interface{} {
// Clickhouse does not need to preprocess the value and can be inserted directly
// So it is not processed here
return gconv.Map(value, gdb.OrmTagForStruct)
}
func (d *Driver) ConvertDataForRecordValue(ctx context.Context, value interface{}) interface{} {
// Clickhouse does not need to preprocess the value and can be inserted directly
// So it is not processed here
return value
}
// InsertIgnore Other queries for modifying data parts are not supported: REPLACE, MERGE, UPSERT, INSERT UPDATE.
func (d *Driver) InsertIgnore(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) {
return nil, errUnsupportedInsertIgnore
}
// InsertAndGetId Other queries for modifying data parts are not supported: REPLACE, MERGE, UPSERT, INSERT UPDATE.
func (d *Driver) InsertAndGetId(ctx context.Context, table string, data interface{}, batch ...int) (int64, error) {
return 0, errUnsupportedInsertGetId
}
// Replace Other queries for modifying data parts are not supported: REPLACE, MERGE, UPSERT, INSERT UPDATE.
func (d *Driver) Replace(ctx context.Context, table string, data interface{}, batch ...int) (sql.Result, error) {
return nil, errUnsupportedReplace
}
func (d *Driver) Begin(ctx context.Context) (tx *gdb.TX, err error) {
return nil, errUnsupportedBegin
}
func (d *Driver) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) error {
return errUnsupportedTransaction
}

View File

@ -0,0 +1,436 @@
package clickhouse
import (
"context"
"fmt"
"github.com/google/uuid"
"testing"
"time"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/grand"
)
const (
sqlVisitsDDL = `
CREATE TABLE IF NOT EXISTS visits (
id UInt64,
duration Float64,
url String,
created DateTime
) ENGINE = MergeTree()
PRIMARY KEY id
ORDER BY id
`
dimSqlDDL = `
CREATE TABLE IF NOT EXISTS dim (
"code" String COMMENT '编码',
"translation" String COMMENT '译文',
"superior" UInt64 COMMENT '上级ID',
"row_number" UInt16 COMMENT '行号',
"is_active" UInt8 COMMENT '是否激活',
"is_preset" UInt8 COMMENT '是否预置',
"category" String COMMENT '类别',
"tree_path" Array(String) COMMENT '树路径',
"id" UInt64 COMMENT '代理主键ID',
"scd" UInt64 COMMENT '缓慢变化维ID',
"version" UInt64 COMMENT 'Merge版本ID',
"sign" Int8 COMMENT '标识位',
"created_by" UInt64 COMMENT '创建者ID',
"created_at" DateTime64(3,'Asia/Shanghai') COMMENT '创建时间',
"updated_by" UInt64 COMMENT '最后修改者ID',
"updated_at" DateTime64(3,'Asia/Shanghai') COMMENT '最后修改时间',
"updated_tick" UInt16 COMMENT '累计修改次数'
) ENGINE = ReplacingMergeTree("version")
ORDER BY ("id","scd")
COMMENT '会计准则';
`
dimSqlDML = `
insert into dim (code, translation, superior, row_number, is_active, is_preset, category, tree_path, id, scd, version, sign, created_by, created_at, updated_by, updated_at, updated_tick)
values ('CN', '{"zh_CN":"中国大陆会计准则","en_US":"Chinese mainland accounting legislation"}', 0, 1, 1, 1, 1, '[''CN'']', 607972403489804288, 0, 0, 0, 607536279118155777, '2017-09-06 00:00:00', 607536279118155777, '2017-09-06 00:00:00', 0),
('HK', '{"zh_CN":"中国香港会计准则","en_US":"Chinese Hong Kong accounting legislation"}', 0, 2, 1, 1, 1, '[''HK'']', 607972558544834566, 0, 0, 0, 607536279118155777, '2017-09-06 00:00:00', 607536279118155777, '2017-09-06 00:00:00', 0);
`
factSqlDDL = `
CREATE TABLE IF NOT EXISTS fact (
"adjustment_level" UInt64 COMMENT '调整层ID',
"data_version" UInt64 COMMENT '数据版本ID',
"accounting_legislation" UInt64 COMMENT '会计准则ID',
"fiscal_year" UInt16 COMMENT '会计年度',
"fiscal_period" UInt8 COMMENT '会计期间',
"fiscal_year_period" UInt32 COMMENT '会计年度期间',
"legal_entity" UInt64 COMMENT '法人主体ID',
"cost_center" UInt64 COMMENT '成本中心ID',
"legal_entity_partner" UInt64 COMMENT '内部关联方ID',
"financial_posting" UInt64 COMMENT '凭证头ID',
"line" UInt16 COMMENT '行号',
"general_ledger_account" UInt64 COMMENT '总账科目ID',
"debit" Decimal64(9) COMMENT '借方金额',
"credit" Decimal64(9) COMMENT '贷方金额',
"transaction_currency" UInt64 COMMENT '交易币种ID',
"debit_tc" Decimal64(9) COMMENT '借方金额(交易币种)',
"credit_tc" Decimal64(9) COMMENT '贷方金额(交易币种)',
"posting_date" Date32 COMMENT '过账日期',
"gc_year" UInt16 COMMENT '公历年',
"gc_quarter" UInt8 COMMENT '公历季',
"gc_month" UInt8 COMMENT '公历月',
"gc_week" UInt8 COMMENT '公历周',
"raw_info" String COMMENT '源信息',
"summary" String COMMENT '摘要',
"id" UInt64 COMMENT '代理主键ID',
"version" UInt64 COMMENT 'Merge版本ID',
"sign" Int8 COMMENT '标识位'
) ENGINE = ReplacingMergeTree("version")
ORDER BY ("adjustment_level","data_version","legal_entity","fiscal_year","fiscal_period","financial_posting","line")
PARTITION BY ("adjustment_level","data_version","legal_entity","fiscal_year","fiscal_period")
COMMENT '数据主表';
`
factSqlDML = `
insert into fact (adjustment_level, data_version, accounting_legislation, fiscal_year, fiscal_period, fiscal_year_period, legal_entity, cost_center, legal_entity_partner, financial_posting, line, general_ledger_account, debit, credit, transaction_currency, debit_tc, credit_tc, posting_date, gc_year, gc_quarter, gc_month, gc_week, raw_info, summary, id, version, sign)
values (607970943242866688, 607973669943119880, 607972403489804288, 2022, 3, 202203, 607974511316307985, 0, 607976190010986520, 607996702456025136, 1, 607985607569838111, 8674.39, 0, 607974898261823505, 8674.39, 0, '2022-03-05', 2022, 1, 3, 11, '{}', '摘要', 607992882741121073, 0, 0),
(607970943242866688, 607973669943119880, 607972403489804288, 2022, 4, 202204, 607974511316307985, 0, 607976190010986520, 607993586419503145, 1, 607985607569838111, 9999.88, 0, 607974898261823505, 9999.88, 0, '2022-04-10', 2022, 2, 4, 18, '{}', '摘要', 607996939140599857, 0, 0);
`
expmSqlDDL = `
CREATE TABLE IF NOT EXISTS data_type (
Col1 UInt8
, Col2 String
, Col3 FixedString(3)
, Col4 UUID
, Col5 Map(String, UInt8)
, Col6 Array(String)
, Col7 Tuple(String, UInt8, Array(Map(String, String)))
, Col8 DateTime
) ENGINE = MergeTree()
PRIMARY KEY Col4
ORDER BY Col4
`
)
func clickhouseConfigDB() gdb.DB {
connect, err := gdb.New(gdb.ConfigNode{
Host: "127.0.0.1",
Port: "9000",
User: "default",
Name: "default",
Type: "clickhouse",
})
gtest.AssertNil(err)
gtest.AssertNE(connect, nil)
return connect
}
func createClickhouseTableVisits(connect gdb.DB) error {
_, err := connect.Exec(context.Background(), sqlVisitsDDL)
return err
}
func createClickhouseTableDim(connect gdb.DB) error {
_, err := connect.Exec(context.Background(), dimSqlDDL)
return err
}
func createClickhouseTableFact(connect gdb.DB) error {
_, err := connect.Exec(context.Background(), factSqlDDL)
return err
}
func createClickhouseExampleTable(connect gdb.DB) error {
_, err := connect.Exec(context.Background(), expmSqlDDL)
return err
}
func dropClickhouseTableVisits(conn gdb.DB) {
sqlStr := fmt.Sprintf("DROP TABLE IF EXISTS `visits`")
_, _ = conn.Exec(context.Background(), sqlStr)
}
func dropClickhouseTableDim(conn gdb.DB) {
sqlStr := fmt.Sprintf("DROP TABLE IF EXISTS `dim`")
_, _ = conn.Exec(context.Background(), sqlStr)
}
func dropClickhouseTableFact(conn gdb.DB) {
sqlStr := fmt.Sprintf("DROP TABLE IF EXISTS `fact`")
_, _ = conn.Exec(context.Background(), sqlStr)
}
func dropClickhouseExampleTable(conn gdb.DB) {
sqlStr := fmt.Sprintf("DROP TABLE IF EXISTS `data_type`")
_, _ = conn.Exec(context.Background(), sqlStr)
}
func TestDriverClickhouse_Create(t *testing.T) {
gtest.AssertNil(createClickhouseTableVisits(clickhouseConfigDB()))
}
func TestDriverClickhouse_New(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertNE(connect, nil)
gtest.AssertNil(connect.PingMaster())
gtest.AssertNil(connect.PingSlave())
}
func TestDriverClickhouse_OpenLink_Ping(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertNE(connect, nil)
gtest.AssertNil(connect.PingMaster())
}
func TestDriverClickhouse_Tables(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertEQ(createClickhouseTableVisits(connect), nil)
defer dropClickhouseTableVisits(connect)
tables, err := connect.Tables(context.Background())
gtest.AssertNil(err)
gtest.AssertNE(len(tables), 0)
}
func TestDriverClickhouse_TableFields_Use_Config(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertNil(createClickhouseTableVisits(connect))
defer dropClickhouseTableVisits(connect)
field, err := connect.TableFields(context.Background(), "visits")
gtest.AssertNil(err)
gtest.AssertEQ(len(field), 4)
gtest.AssertNQ(field, nil)
}
func TestDriverClickhouse_TableFields_Use_Link(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertNil(createClickhouseTableVisits(connect))
defer dropClickhouseTableVisits(connect)
field, err := connect.TableFields(context.Background(), "visits")
gtest.AssertNil(err)
gtest.AssertEQ(len(field), 4)
gtest.AssertNQ(field, nil)
}
func TestDriverClickhouse_Transaction(t *testing.T) {
connect := clickhouseConfigDB()
defer dropClickhouseTableVisits(connect)
gtest.AssertNE(connect.Transaction(context.Background(), func(ctx context.Context, tx *gdb.TX) error {
return nil
}), nil)
}
func TestDriverClickhouse_InsertIgnore(t *testing.T) {
connect := clickhouseConfigDB()
_, err := connect.InsertIgnore(context.Background(), "", nil)
gtest.AssertEQ(err, errUnsupportedInsertIgnore)
}
func TestDriverClickhouse_InsertAndGetId(t *testing.T) {
connect := clickhouseConfigDB()
_, err := connect.InsertAndGetId(context.Background(), "", nil)
gtest.AssertEQ(err, errUnsupportedInsertGetId)
}
func TestDriverClickhouse_InsertOne(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertEQ(createClickhouseTableVisits(connect), nil)
defer dropClickhouseTableVisits(connect)
_, err := connect.Model("visits").Data(g.Map{
"duration": float64(grand.Intn(999)),
"url": gconv.String(grand.Intn(999)),
"created": time.Now(),
}).Insert()
gtest.AssertNil(err)
}
func TestDriverClickhouse_InsertMany(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertEQ(createClickhouseTableVisits(connect), nil)
defer dropClickhouseTableVisits(connect)
tx, err := connect.Begin(context.Background())
gtest.AssertEQ(err, errUnsupportedBegin)
gtest.AssertNil(tx)
}
func TestDriverClickhouse_Insert(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertEQ(createClickhouseTableVisits(connect), nil)
defer dropClickhouseTableVisits(connect)
type insertItem struct {
Id uint64 `orm:"id"`
Duration float64 `orm:"duration"`
Url string `orm:"url"`
Created time.Time `orm:"created"`
}
var (
insertUrl = "https://goframe.org"
total = 0
item = insertItem{
Duration: 1,
Url: insertUrl,
Created: time.Now(),
}
)
_, err := connect.Model("visits").Data(item).Insert()
gtest.AssertNil(err)
_, err = connect.Model("visits").Data(item).Save()
gtest.AssertNil(err)
total, err = connect.Model("visits").Count()
gtest.AssertNil(err)
gtest.AssertEQ(total, 2)
var list []*insertItem
for i := 0; i < 50; i++ {
list = append(list, &insertItem{
Duration: float64(grand.Intn(999)),
Url: insertUrl,
Created: time.Now(),
})
}
_, err = connect.Model("visits").Data(list).Insert()
gtest.AssertNil(err)
_, err = connect.Model("visits").Data(list).Save()
gtest.AssertNil(err)
total, err = connect.Model("visits").Count()
gtest.AssertNil(err)
gtest.AssertEQ(total, 102)
}
func TestDriverClickhouse_Insert_Use_Exec(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertEQ(createClickhouseTableFact(connect), nil)
defer dropClickhouseTableFact(connect)
_, err := connect.Exec(context.Background(), factSqlDML)
gtest.AssertNil(err)
}
func TestDriverClickhouse_Delete(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertEQ(createClickhouseTableVisits(connect), nil)
defer dropClickhouseTableVisits(connect)
_, err := connect.Model("visits").Where("created >", "2021-01-01 00:00:00").Delete()
gtest.AssertNil(err)
}
func TestDriverClickhouse_Update(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertEQ(createClickhouseTableVisits(connect), nil)
defer dropClickhouseTableVisits(connect)
_, err := connect.Model("visits").Where("created > ", "2021-01-01 15:15:15").Data(g.Map{
"created": time.Now().Format("2006-01-02 15:04:05"),
}).Update()
gtest.AssertNil(err)
}
func TestDriverClickhouse_Replace(t *testing.T) {
connect := clickhouseConfigDB()
_, err := connect.Replace(context.Background(), "", nil)
gtest.AssertEQ(err, errUnsupportedReplace)
}
func TestDriverClickhouse_DoFilter(t *testing.T) {
rawSQL := "select * from visits where 1 = 1"
this := Driver{}
replaceSQL, _, err := this.DoFilter(nil, nil, rawSQL, []interface{}{1})
gtest.AssertNil(err)
gtest.AssertEQ(rawSQL, replaceSQL)
// this SQL can't run ,clickhouse will report an error because there is no WHERE statement
rawSQL = "update visit set url = '1'"
replaceSQL, _, err = this.DoFilter(nil, nil, rawSQL, []interface{}{1})
gtest.AssertEQ(err, errNotCondition)
// this SQL can't run ,clickhouse will report an error because there is no WHERE statement
rawSQL = "delete from visit"
replaceSQL, _, err = this.DoFilter(nil, nil, rawSQL, []interface{}{1})
gtest.AssertEQ(err, errNotCondition)
rawSQL = "update visit set url = '1' where url = '0'"
replaceSQL, _, err = this.DoFilter(nil, nil, rawSQL, []interface{}{1})
gtest.AssertNil(err)
gtest.AssertEQ(replaceSQL, "ALTER TABLE visit UPDATE url = '1' WHERE url = '0'")
rawSQL = "delete from visit where url='0'"
replaceSQL, _, err = this.DoFilter(nil, nil, rawSQL, []interface{}{1})
gtest.AssertNil(err)
gtest.AssertEQ(replaceSQL, "ALTER TABLE visit DELETE WHERE url = '0'")
}
func TestDriverClickhouse_Select(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertNil(createClickhouseTableVisits(connect))
defer dropClickhouseTableVisits(connect)
_, err := connect.Model("visits").Data(g.Map{
"url": "goframe.org",
"duration": float64(1),
}).Insert()
gtest.AssertNil(err)
temp, err := connect.Model("visits").Where("url", "goframe.org").Where("duration >= ", 1).One()
gtest.AssertNil(err)
gtest.AssertEQ(temp.IsEmpty(), false)
_, err = connect.Model("visits").Data(g.Map{
"url": "goframe.org",
"duration": float64(2),
}).Insert()
gtest.AssertNil(err)
data, err := connect.Model("visits").Where("url", "goframe.org").Where("duration >= ", 1).All()
gtest.AssertNil(err)
gtest.AssertEQ(len(data), 2)
}
func TestDriverClickhouse_Exec_OPTIMIZE(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertNil(createClickhouseTableVisits(connect))
defer dropClickhouseTableVisits(connect)
sqlStr := "OPTIMIZE table visits"
_, err := connect.Exec(context.Background(), sqlStr)
gtest.AssertNil(err)
}
func TestDriverClickhouse_ExecInsert(t *testing.T) {
connect := clickhouseConfigDB()
gtest.AssertEQ(createClickhouseTableDim(connect), nil)
defer dropClickhouseTableDim(connect)
_, err := connect.Exec(context.Background(), dimSqlDML)
gtest.AssertNil(err)
}
func TestDriverClickhouse_BatchInsert(t *testing.T) {
// example from
// https://github.com/ClickHouse/clickhouse-go/blob/v2/examples/std/batch/main.go
connect := clickhouseConfigDB()
gtest.AssertNil(createClickhouseExampleTable(connect))
defer dropClickhouseExampleTable(connect)
insertData := []g.Map{}
for i := 0; i < 10000; i++ {
insertData = append(insertData, g.Map{
"Col1": uint8(42),
"Col2": "ClickHouse",
"Col3": "Inc",
"Col4": uuid.New(),
"Col5": map[string]uint8{"key": 1}, // Map(String, UInt8)
"Col6": []string{"Q", "W", "E", "R", "T", "Y"}, // Array(String)
"Col7": []interface{}{ // Tuple(String, UInt8, Array(Map(String, String)))
"String Value", uint8(5), []map[string]string{
map[string]string{"key": "value"},
map[string]string{"key": "value"},
map[string]string{"key": "value"},
},
},
"Col8": time.Now(),
})
}
_, err := connect.Model("data_type").Data(insertData).Insert()
gtest.AssertNil(err)
count, err := connect.Model("data_type").Where("Col2", "ClickHouse").Where("Col3", "Inc").Count()
gtest.AssertNil(err)
gtest.AssertEQ(count, 10000)
}
func TestDriverClickhouse_Open(t *testing.T) {
// link
// DSM
// clickhouse://username:password@host1:9000,host2:9000/database?dial_timeout=200ms&max_execution_time=60
link := "clickhouse://default@127.0.0.1:9000,127.0.0.1:9000/default?dial_timeout=200ms&max_execution_time=60"
db, err := gdb.New(gdb.ConfigNode{
Link: link,
Type: "clickhouse",
})
gtest.AssertNil(err)
gtest.AssertNil(db.PingMaster())
}

View File

@ -3,11 +3,10 @@ module github.com/gogf/gf/contrib/drivers/clickhouse/v2
go 1.15
require (
github.com/ClickHouse/clickhouse-go v1.5.2
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.1.0 // indirect
github.com/stretchr/testify v1.7.0 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.0.12
github.com/gogf/gf/v2 v2.0.0
github.com/google/uuid v1.3.0
github.com/longbridgeapp/sqlparser v0.3.1
)
replace github.com/gogf/gf/v2 => ../../../

View File

@ -1,32 +1,201 @@
github.com/ClickHouse/clickhouse-go v1.5.2 h1:yXgaOZ8WEHrd+okvZXjzulSt1zS33nM4ujfx9lVncl8=
github.com/ClickHouse/clickhouse-go v1.5.2/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/ClickHouse/clickhouse-go v1.5.3 h1:Vok8zUb/wlqc9u8oEqQzBMBRDoFd8NxPRqgYEqMnV88=
github.com/ClickHouse/clickhouse-go v1.5.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/ClickHouse/clickhouse-go/v2 v2.0.12 h1:Nbl/NZwoM6LGJm7smNBgvtdr/rxjlIssSW3eG/Nmb9E=
github.com/ClickHouse/clickhouse-go/v2 v2.0.12/go.mod h1:u4RoNQLLM2W6hNSPYrIESLJqaWSInZVmfM+MlaAhXcg=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58 h1:F1EaeKL/ta07PY/k9Os/UFtwERei2/XzGemhpGnBKNg=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-redis/redis/v8 v8.11.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/go-test/deep v1.0.7 h1:/VSMRlnY/JSyqxQUzQLKVMAskpY/NZKFA5j2P+0pP2M=
github.com/go-test/deep v1.0.7/go.mod h1:QV8Hv/iy04NyLBxAdO9njL0iVPN1S4d/A3NVv1V36o8=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/longbridgeapp/sqlparser v0.3.1 h1:iWOZWGIFgQrJRgobLXUNJdvqGRpbVXkyKUKUA5CNJBE=
github.com/longbridgeapp/sqlparser v0.3.1/go.mod h1:GIHaUq8zvYyHLCLMJJykx1CdM6LHtkUih/QaJXySSx4=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.16.0 h1:6gjqkI8iiRHMvdccRJM8rVKjCWk6ZIm6FTm3ddIe4/c=
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/paulmach/orb v0.4.0 h1:ilp1MQjRapLJ1+qcays1nZpe0mvkCY+b8JU/qBKRZ1A=
github.com/paulmach/orb v0.4.0/go.mod h1:FkcWtplUAIVqAuhAOV2d3rpbnQyliDOjOcLW9dUrfdU=
github.com/paulmach/protoscan v0.2.1-0.20210522164731-4e53c6875432/go.mod h1:2sV+uZ/oQh66m4XJVZm5iqUZ62BN88Ex1E+TTS0nLzI=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
go.opentelemetry.io/otel v1.4.1 h1:QbINgGDDcoQUoMJa2mMaWno49lja9sHwp6aoa2n3a4g=
go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4=
go.opentelemetry.io/otel/sdk v1.0.0 h1:BNPMYUONPNbLneMttKSjQhOTlFLOD9U22HNG1KrIN2Y=
go.opentelemetry.io/otel/sdk v1.0.0/go.mod h1:PCrDHlSy5x1kjezSdL37PhbFUMjrsLRshJ2zCzeXwbM=
go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
go.opentelemetry.io/otel/trace v1.4.1 h1:O+16qcdTrT7zxv2J6GejTPFinSwA++cYerC5iSiF8EQ=
go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08 h1:WecRHqgE09JBkh/584XIE6PMz5KKE/vER4izNUi30AQ=
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y=
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -4,7 +4,7 @@ go 1.15
require (
github.com/denisenkom/go-mssqldb v0.11.0
github.com/gogf/gf/v2 v2.0.0-rc
github.com/gogf/gf/v2 v2.0.0
)
replace github.com/gogf/gf/v2 => ../../../

View File

@ -223,7 +223,7 @@ func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string,
return nil, err
}
result, err = d.DoGetAll(ctx, link, `SELECT NAME FROM SYSOBJECTS WHERE XTYPE='U' AND STATUS >= 0 ORDER BY NAME`)
result, err = d.DoSelect(ctx, link, `SELECT NAME FROM SYSOBJECTS WHERE XTYPE='U' AND STATUS >= 0 ORDER BY NAME`)
if err != nil {
return
}
@ -289,7 +289,7 @@ ORDER BY a.id,a.colorder`,
table,
)
structureSql, _ = gregex.ReplaceString(`[\n\r\s]+`, " ", gstr.Trim(structureSql))
result, err = d.DoGetAll(ctx, link, structureSql)
result, err = d.DoSelect(ctx, link, structureSql)
if err != nil {
return nil
}

View File

@ -2,6 +2,6 @@ module github.com/gogf/gf/contrib/drivers/mysql/v2
go 1.15
require github.com/gogf/gf/v2 v2.0.0-rc
require github.com/gogf/gf/v2 v2.0.0
replace github.com/gogf/gf/v2 => ../../../

View File

@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/drivers/oracle/v2
go 1.15
require (
github.com/gogf/gf/v2 v2.0.0-rc
github.com/gogf/gf/v2 v2.0.0
github.com/mattn/go-oci8 v0.1.1
)

View File

@ -194,7 +194,7 @@ func (d *Driver) parseSql(sql string) string {
// Note that it ignores the parameter `schema` in oracle database, as it is not necessary.
func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string, err error) {
var result gdb.Result
result, err = d.DoGetAll(ctx, nil, "SELECT TABLE_NAME FROM USER_TABLES ORDER BY TABLE_NAME")
result, err = d.DoSelect(ctx, nil, "SELECT TABLE_NAME FROM USER_TABLES ORDER BY TABLE_NAME")
if err != nil {
return
}
@ -245,7 +245,7 @@ FROM USER_TAB_COLUMNS WHERE TABLE_NAME = '%s' ORDER BY COLUMN_ID`,
return nil
}
structureSql, _ = gregex.ReplaceString(`[\n\r\s]+`, " ", gstr.Trim(structureSql))
result, err = d.DoGetAll(ctx, link, structureSql)
result, err = d.DoSelect(ctx, link, structureSql)
if err != nil {
return nil
}

View File

@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/drivers/pgsql/v2
go 1.15
require (
github.com/gogf/gf/v2 v2.0.0-rc
github.com/gogf/gf/v2 v2.0.0
github.com/lib/pq v1.10.4
)

View File

@ -142,7 +142,7 @@ func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string,
schema[0],
)
}
result, err = d.DoGetAll(ctx, link, query)
result, err = d.DoSelect(ctx, link, query)
if err != nil {
return
}
@ -198,7 +198,7 @@ ORDER BY a.attnum`,
return nil
}
structureSql, _ = gregex.ReplaceString(`[\n\r\s]+`, " ", gstr.Trim(structureSql))
result, err = d.DoGetAll(ctx, link, structureSql)
result, err = d.DoSelect(ctx, link, structureSql)
if err != nil {
return nil
}

View File

@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/drivers/sqlite/v2
go 1.15
require (
github.com/gogf/gf/v2 v2.0.0-rc
github.com/gogf/gf/v2 v2.0.0
github.com/mattn/go-sqlite3 v1.14.10
)

View File

@ -106,7 +106,7 @@ func (d *Driver) Tables(ctx context.Context, schema ...string) (tables []string,
return nil, err
}
result, err = d.DoGetAll(ctx, link, `SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`)
result, err = d.DoSelect(ctx, link, `SELECT NAME FROM SQLITE_MASTER WHERE TYPE='table' ORDER BY NAME`)
if err != nil {
return
}
@ -141,7 +141,7 @@ func (d *Driver) TableFields(ctx context.Context, table string, schema ...string
if link, err = d.SlaveLink(useSchema); err != nil {
return nil
}
result, err = d.DoGetAll(ctx, link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, table))
result, err = d.DoSelect(ctx, link, fmt.Sprintf(`PRAGMA TABLE_INFO(%s)`, table))
if err != nil {
return nil
}

View File

@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/registry/etcd/v2
go 1.15
require (
github.com/gogf/gf/v2 v2.0.0-rc2
github.com/gogf/gf/v2 v2.0.0
go.etcd.io/etcd/client/v3 v3.5.1
)

View File

@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/trace/jaeger/v2
go 1.15
require (
github.com/gogf/gf/v2 v2.0.0-rc2
github.com/gogf/gf/v2 v2.0.0
go.opentelemetry.io/otel/exporters/jaeger v1.3.0
go.opentelemetry.io/otel/sdk v1.3.0
)

View File

@ -41,19 +41,19 @@ var (
func TestEncrypt(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
data, err := gaes.Encrypt(content, key_16)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(data, []byte(content_16))
data, err = gaes.Encrypt(content, key_24)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(data, []byte(content_24))
data, err = gaes.Encrypt(content, key_32)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(data, []byte(content_32))
data, err = gaes.Encrypt(content, key_16, iv)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(data, []byte(content_16_iv))
data, err = gaes.Encrypt(content, key_32, iv)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(data, []byte(content_32_iv))
})
}
@ -61,23 +61,23 @@ func TestEncrypt(t *testing.T) {
func TestDecrypt(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
decrypt, err := gaes.Decrypt([]byte(content_16), key_16)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(decrypt, content)
decrypt, err = gaes.Decrypt([]byte(content_24), key_24)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(decrypt, content)
decrypt, err = gaes.Decrypt([]byte(content_32), key_32)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(decrypt, content)
decrypt, err = gaes.Decrypt([]byte(content_16_iv), key_16, iv)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(decrypt, content)
decrypt, err = gaes.Decrypt([]byte(content_32_iv), key_32, iv)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(decrypt, content)
decrypt, err = gaes.Decrypt([]byte(content_32_iv), keys, iv)
@ -134,7 +134,7 @@ func TestEncryptCFB(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var padding int = 0
data, err := gaes.EncryptCFB(content, key_16, &padding, iv)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(padding, padding_size)
t.Assert(data, []byte(content_16_cfb))
})
@ -143,7 +143,7 @@ func TestEncryptCFB(t *testing.T) {
func TestDecryptCFB(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
decrypt, err := gaes.DecryptCFB([]byte(content_16_cfb), key_16, padding_size, iv)
t.Assert(err, nil)
t.AssertNil(err)
t.Assert(decrypt, content)
})
}

View File

@ -65,7 +65,7 @@ func TestEncryptFile(t *testing.T) {
file, err := os.Create(path)
defer os.Remove(path)
defer file.Close()
t.Assert(err, nil)
t.AssertNil(err)
_, _ = file.Write([]byte("Hello Go Frame"))
encryptFile, _ := gmd5.EncryptFile(path)
t.AssertEQ(encryptFile, result)

View File

@ -48,7 +48,7 @@ func TestEncryptFile(t *testing.T) {
file, err := os.Create(path)
defer os.Remove(path)
defer file.Close()
t.Assert(err, nil)
t.AssertNil(err)
_, _ = file.Write([]byte("Hello Go Frame"))
encryptFile, _ := gsha1.EncryptFile(path)
t.AssertEQ(encryptFile, result)

View File

@ -20,6 +20,7 @@ import (
"github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/os/gcache"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/util/grand"
)
@ -94,15 +95,18 @@ type DB interface {
// Internal APIs for CURD, which can be overwritten by custom CURD implements.
// ===========================================================================
DoGetAll(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoGetAll.
DoSelect(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoSelect.
DoInsert(ctx context.Context, link Link, table string, data List, option DoInsertOption) (result sql.Result, err error) // See Core.DoInsert.
DoUpdate(ctx context.Context, link Link, table string, data interface{}, condition string, args ...interface{}) (result sql.Result, err error) // See Core.DoUpdate.
DoDelete(ctx context.Context, link Link, table string, condition string, args ...interface{}) (result sql.Result, err error) // See Core.DoDelete.
DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoQuery.
DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) // See Core.DoExec.
DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) // See Core.DoFilter.
DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) // See Core.DoCommit.
DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error) // See Core.DoPrepare.
DoQuery(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) // See Core.DoQuery.
DoExec(ctx context.Context, link Link, sql string, args ...interface{}) (result sql.Result, err error) // See Core.DoExec.
DoFilter(ctx context.Context, link Link, sql string, args []interface{}) (newSql string, newArgs []interface{}, err error) // See Core.DoFilter.
DoCommit(ctx context.Context, in DoCommitInput) (out DoCommitOutput, err error) // See Core.DoCommit.
DoPrepare(ctx context.Context, link Link, sql string) (*Stmt, error) // See Core.DoPrepare.
// ===========================================================================
// Query APIs for convenience purpose.
@ -211,13 +215,12 @@ type Driver interface {
}
// Link is a common database function wrapper interface.
// Note that, any operation using `Link` will have no SQL logging.
type Link interface {
Query(sql string, args ...interface{}) (*sql.Rows, error)
Exec(sql string, args ...interface{}) (sql.Result, error)
Prepare(sql string) (*sql.Stmt, error)
QueryContext(ctx context.Context, sql string, args ...interface{}) (*sql.Rows, error)
ExecContext(ctx context.Context, sql string, args ...interface{}) (sql.Result, error)
PrepareContext(ctx context.Context, sql string) (*sql.Stmt, error)
IsOnMaster() bool
IsTransaction() bool
}
@ -237,10 +240,10 @@ type Sql struct {
// DoInsertOption is the input struct for function DoInsert.
type DoInsertOption struct {
OnDuplicateStr string
OnDuplicateMap map[string]interface{}
InsertOption int // Insert operation.
BatchCount int // Batch count for batch inserting.
OnDuplicateStr string // Custom string for `on duplicated` statement.
OnDuplicateMap map[string]interface{} // Custom key-value map from `OnDuplicateEx` function for `on duplicated` statement.
InsertOption int // Insert operation in constant value.
BatchCount int // Batch count for batch inserting.
}
// TableField is the struct for table field.
@ -277,16 +280,16 @@ const (
queryTypeCount = 1
unionTypeNormal = 0
unionTypeAll = 1
defaultBatchNumber = 10 // Per count for batch insert/replace/save.
defaultMaxIdleConnCount = 10 // Max idle connection count in pool.
defaultMaxOpenConnCount = 0 // Max open connection count in pool. Default is no limit.
defaultMaxConnLifeTime = 30 * time.Second // Max lifetime for per connection in pool in seconds.
ctxTimeoutTypeExec = iota
ctxTimeoutTypeQuery
ctxTimeoutTypePrepare
commandEnvKeyForDryRun = "gf.gdb.dryrun"
modelForDaoSuffix = `ForDao`
dbRoleSlave = `slave`
commandEnvKeyForDryRun = "gf.gdb.dryrun"
modelForDaoSuffix = `ForDao`
dbRoleSlave = `slave`
contextKeyForDB gctx.StrKey = `DBInContext`
)
const (
@ -409,7 +412,8 @@ func doNewByNode(node ConfigNode, group string) (db DB, err error) {
return c.db, nil
}
errorMsg := `cannot find database driver for specified database type "%s"`
errorMsg += `, did you misspell type name "%s" or forget importing the database driver?`
errorMsg += `, did you misspell type name "%s" or forget importing the database driver? `
errorMsg += `possible reference: https://github.com/gogf/gf/tree/master/contrib/drivers`
return nil, gerror.NewCodef(gcode.CodeInvalidConfiguration, errorMsg, node.Type, node.Type)
}
@ -517,8 +521,11 @@ func getConfigNodeByWeight(cg ConfigGroup) *ConfigNode {
// The parameter `master` specifies whether retrieves master node connection if
// master-slave nodes are configured.
func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error) {
var (
ctx = c.db.GetCtx()
node *ConfigNode
)
// Load balance.
var node *ConfigNode
if c.group != "" {
node, err = getConfigNodeByGroup(c.group, master)
if err != nil {
@ -544,20 +551,12 @@ func (c *Core) getSqlDb(master bool, schema ...string) (sqlDb *sql.DB, err error
}
// Cache the underlying connection pool object by node.
v := c.links.GetOrSetFuncLock(node.String(), func() interface{} {
intlog.Printf(
c.db.GetCtx(),
`open new connection, master:%#v, config:%#v, node:%#v`,
master, c.config, node,
)
intlog.Printf(ctx, `open new connection, master:%#v, config:%#v, node:%#v`, master, c.config, node)
defer func() {
if err != nil {
intlog.Printf(c.db.GetCtx(), `open new connection failed: %v, %#v`, err, node)
intlog.Printf(ctx, `open new connection failed: %v, %#v`, err, node)
} else {
intlog.Printf(
c.db.GetCtx(),
`open new connection success, master:%#v, config:%#v, node:%#v`,
master, c.config, node,
)
intlog.Printf(ctx, `open new connection success, master:%#v, config:%#v, node:%#v`, master, c.config, node)
}
}()

View File

@ -18,6 +18,7 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/internal/reflection"
"github.com/gogf/gf/v2/internal/utils"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
@ -44,7 +45,6 @@ func (c *Core) Ctx(ctx context.Context) DB {
configNode = c.db.GetConfig()
)
*newCore = *c
newCore.ctx = ctx
// It creates a new DB object, which is commonly a wrapper for object `Core`.
newCore.db, err = driverMap[configNode.Type].New(newCore, configNode)
if err != nil {
@ -52,22 +52,25 @@ func (c *Core) Ctx(ctx context.Context) DB {
// Do not let it continue.
panic(err)
}
newCore.ctx = WithDB(ctx, newCore.db)
newCore.ctx = c.InjectInternalCtxData(newCore.ctx)
return newCore.db
}
// GetCtx returns the context for current DB.
// It returns `context.Background()` is there's no context previously set.
func (c *Core) GetCtx() context.Context {
if c.ctx != nil {
return c.ctx
ctx := c.ctx
if ctx == nil {
ctx = context.TODO()
}
return context.TODO()
return c.InjectInternalCtxData(ctx)
}
// GetCtxTimeout returns the context and cancel function for specified timeout type.
func (c *Core) GetCtxTimeout(timeoutType int, ctx context.Context) (context.Context, context.CancelFunc) {
func (c *Core) GetCtxTimeout(ctx context.Context, timeoutType int) (context.Context, context.CancelFunc) {
if ctx == nil {
ctx = c.GetCtx()
ctx = c.db.GetCtx()
} else {
ctx = context.WithValue(ctx, "WrappedByGetCtxTimeout", nil)
}
@ -144,11 +147,11 @@ func (c *Core) Slave(schema ...string) (*sql.DB, error) {
// GetAll queries and returns data records from database.
func (c *Core) GetAll(ctx context.Context, sql string, args ...interface{}) (Result, error) {
return c.db.DoGetAll(ctx, nil, sql, args...)
return c.db.DoSelect(ctx, nil, sql, args...)
}
// DoGetAll queries and returns data records from database.
func (c *Core) DoGetAll(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) {
// DoSelect queries and returns data records from database.
func (c *Core) DoSelect(ctx context.Context, link Link, sql string, args ...interface{}) (result Result, err error) {
return c.db.DoQuery(ctx, link, sql, args...)
}
@ -167,7 +170,7 @@ func (c *Core) GetOne(ctx context.Context, sql string, args ...interface{}) (Rec
// GetArray queries and returns data values as slice from database.
// Note that if there are multiple columns in the result, it returns just one column values randomly.
func (c *Core) GetArray(ctx context.Context, sql string, args ...interface{}) ([]Value, error) {
all, err := c.db.DoGetAll(ctx, nil, sql, args...)
all, err := c.db.DoSelect(ctx, nil, sql, args...)
if err != nil {
return nil, err
}
@ -201,7 +204,7 @@ func (c *Core) GetStructs(ctx context.Context, pointer interface{}, sql string,
// the conversion. If parameter `pointer` is type of slice, it calls GetStructs internally
// for conversion.
func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, args ...interface{}) error {
reflectInfo := utils.OriginTypeAndKind(pointer)
reflectInfo := reflection.OriginTypeAndKind(pointer)
if reflectInfo.InputKind != reflect.Ptr {
return gerror.NewCodef(
gcode.CodeInvalidParameter,
@ -239,7 +242,7 @@ func (c *Core) GetValue(ctx context.Context, sql string, args ...interface{}) (V
// GetCount queries and returns the count from database.
func (c *Core) GetCount(ctx context.Context, sql string, args ...interface{}) (int, error) {
// If the query fields do not contains function "COUNT",
// If the query fields do not contain function "COUNT",
// it replaces the sql string and adds the "COUNT" function to the fields.
if !gregex.IsMatchString(`(?i)SELECT\s+COUNT\(.+\)\s+FROM`, sql) {
sql, _ = gregex.ReplaceString(`(?i)(SELECT)\s+(.+)\s+(FROM)`, `$1 COUNT($2) $3`, sql)
@ -253,15 +256,17 @@ func (c *Core) GetCount(ctx context.Context, sql string, args ...interface{}) (i
// Union does "(SELECT xxx FROM xxx) UNION (SELECT xxx FROM xxx) ..." statement.
func (c *Core) Union(unions ...*Model) *Model {
return c.doUnion(unionTypeNormal, unions...)
var ctx = c.db.GetCtx()
return c.doUnion(ctx, unionTypeNormal, unions...)
}
// UnionAll does "(SELECT xxx FROM xxx) UNION ALL (SELECT xxx FROM xxx) ..." statement.
func (c *Core) UnionAll(unions ...*Model) *Model {
return c.doUnion(unionTypeAll, unions...)
var ctx = c.db.GetCtx()
return c.doUnion(ctx, unionTypeAll, unions...)
}
func (c *Core) doUnion(unionType int, unions ...*Model) *Model {
func (c *Core) doUnion(ctx context.Context, unionType int, unions ...*Model) *Model {
var (
unionTypeStr string
composedSqlStr string
@ -273,7 +278,7 @@ func (c *Core) doUnion(unionType int, unions ...*Model) *Model {
unionTypeStr = "UNION"
}
for _, v := range unions {
sqlWithHolder, holderArgs := v.getFormattedSqlAndArgs(queryTypeNormal, false)
sqlWithHolder, holderArgs := v.getFormattedSqlAndArgs(ctx, queryTypeNormal, false)
if composedSqlStr == "" {
composedSqlStr += fmt.Sprintf(`(%s)`, sqlWithHolder)
} else {
@ -286,10 +291,11 @@ func (c *Core) doUnion(unionType int, unions ...*Model) *Model {
// PingMaster pings the master node to check authentication or keeps the connection alive.
func (c *Core) PingMaster() error {
var ctx = c.db.GetCtx()
if master, err := c.db.Master(); err != nil {
return err
} else {
if err = master.PingContext(c.GetCtx()); err != nil {
if err = master.PingContext(ctx); err != nil {
err = gerror.WrapCode(gcode.CodeDbOperationError, err, `master.Ping failed`)
}
return err
@ -298,10 +304,11 @@ func (c *Core) PingMaster() error {
// PingSlave pings the slave node to check authentication or keeps the connection alive.
func (c *Core) PingSlave() error {
var ctx = c.db.GetCtx()
if slave, err := c.db.Slave(); err != nil {
return err
} else {
if err = slave.PingContext(c.GetCtx()); err != nil {
if err = slave.PingContext(ctx); err != nil {
err = gerror.WrapCode(gcode.CodeDbOperationError, err, `slave.Ping failed`)
}
return err
@ -660,21 +667,22 @@ func (c *Core) writeSqlToLogger(ctx context.Context, sql *Sql) {
// HasTable determine whether the table name exists in the database.
func (c *Core) HasTable(name string) (bool, error) {
result, err := c.GetCache().GetOrSetFuncLock(
c.GetCtx(),
fmt.Sprintf(`HasTable: %s`, name),
func(ctx context.Context) (interface{}, error) {
tableList, err := c.db.Tables(ctx)
if err != nil {
return false, err
var (
ctx = c.db.GetCtx()
cacheKey = fmt.Sprintf(`HasTable: %s`, name)
)
result, err := c.GetCache().GetOrSetFuncLock(ctx, cacheKey, func(ctx context.Context) (interface{}, error) {
tableList, err := c.db.Tables(ctx)
if err != nil {
return false, err
}
for _, table := range tableList {
if table == name {
return true, nil
}
for _, table := range tableList {
if table == name {
return true, nil
}
}
return false, nil
}, 0,
}
return false, nil
}, 0,
)
if err != nil {
return false, err

View File

@ -0,0 +1,66 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gdb
import (
"context"
"github.com/gogf/gf/v2/os/gctx"
)
// internalCtxData stores data in ctx for internal usage purpose.
type internalCtxData struct {
// Operation DB.
DB DB
// The first column in result response from database server.
// This attribute is used for Value/Count selection statement purpose,
// which is to avoid HOOK handler that might modify the result columns
// that can confuse the Value/Count selection statement logic.
FirstResultColumn string
}
const (
internalCtxDataKeyInCtx gctx.StrKey = "InternalCtxData"
// `ignoreResultKeyInCtx` is a mark for some db drivers that do not support `RowsAffected` function,
// for example: `clickhouse`. The `clickhouse` does not support fetching insert/update results,
// but returns errors when execute `RowsAffected`. It here ignores the calling of `RowsAffected`
// to avoid triggering errors, rather than ignoring errors after they are triggered.
ignoreResultKeyInCtx gctx.StrKey = "IgnoreResult"
)
func (c *Core) InjectInternalCtxData(ctx context.Context) context.Context {
// If the internal data is already injected, it does nothing.
if ctx.Value(internalCtxDataKeyInCtx) != nil {
return ctx
}
return context.WithValue(ctx, internalCtxDataKeyInCtx, &internalCtxData{
DB: c.db,
})
}
func (c *Core) GetInternalCtxDataFromCtx(ctx context.Context) *internalCtxData {
if v := ctx.Value(internalCtxDataKeyInCtx); v != nil {
return v.(*internalCtxData)
}
return nil
}
func (c *Core) InjectIgnoreResult(ctx context.Context) context.Context {
if ctx.Value(ignoreResultKeyInCtx) != nil {
return ctx
}
return context.WithValue(ctx, ignoreResultKeyInCtx, true)
}
func (c *Core) GetIgnoreResultFromCtx(ctx context.Context) bool {
if ctx.Value(ignoreResultKeyInCtx) != nil {
return true
}
return false
}

View File

@ -12,7 +12,8 @@ import (
// dbLink is used to implement interface Link for DB.
type dbLink struct {
*sql.DB
*sql.DB // Underlying DB object.
isOnMaster bool // isOnMaster marks whether current link is operated on master node.
}
// txLink is used to implement interface Link for TX.
@ -21,11 +22,22 @@ type txLink struct {
}
// IsTransaction returns if current Link is a transaction.
func (*dbLink) IsTransaction() bool {
func (l *dbLink) IsTransaction() bool {
return false
}
// IsOnMaster checks and returns whether current link is operated on master node.
func (l *dbLink) IsOnMaster() bool {
return l.isOnMaster
}
// IsTransaction returns if current Link is a transaction.
func (*txLink) IsTransaction() bool {
func (l *txLink) IsTransaction() bool {
return true
}
// IsOnMaster checks and returns whether current link is operated on master node.
// Note that, transaction operation is always operated on master node.
func (l *txLink) IsOnMaster() bool {
return true
}

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