Compare commits

...

366 Commits

Author SHA1 Message Date
847f016cc9 new version v2.2.0 (#2185) 2022-10-10 20:15:17 +08:00
c613dc8c5c feat: temporarily disable the unit testing of the Polaris configuration center (#2183)
* feat: temporarily annotate the unit test of Polaris configuration Center

* fix: remove
2022-10-09 21:42:32 +08:00
182a393050 package comments and readme update (#2182) 2022-10-09 21:23:55 +08:00
6cb91021cf feat: create polaris config (#2170)
* feat: create polaris config

* feat: improve code

* feat: modify config file path

Co-authored-by: John Guo <john@johng.cn>
2022-10-09 19:20:33 +08:00
2be9bb970b add function ZipPathContent for package gcompress (#2179)
add function ZipPathContent for package gcompress
2022-10-09 19:19:10 +08:00
ea396a3925 feat: improve glog for polaris register (#2178)
feat: improve glog
2022-10-09 09:10:02 +08:00
b1611fee1b improve port listening for ghttp.Server (#2175)
* version updates

* fix issue #2172

* improve port listening for ghttp.Server

* UT cases update

* UT cases update

* add GetListenedPort/GetListenedAddress for gtcp.Server

* UT cases update for package gudp

* up
2022-10-08 21:45:21 +08:00
dba903c13b add WithUUID for package gtrace (#2176)
* add WithUUID for package gtrace

* feat: improve import

Co-authored-by: houseme <housemecn@gmail.com>
2022-10-08 21:44:42 +08:00
7cb5fbe684 fix issue #1965 (#2177) 2022-10-08 21:42:30 +08:00
d7ae5624c8 fix issue #1965 (#2174)
Co-authored-by: houseme <housemecn@gmail.com>
2022-10-08 19:36:05 +08:00
f1455ad37a fix issue #2172 (#2173)
* version updates

* fix issue #2172
2022-10-08 11:46:38 +08:00
127e8af6a6 add gcfg.Adapter implements using apollo service (#2165)
* version updates

* up

* add watch feature for package kubecm

* feat: support apollo as Adapter (#2143)

* feat: support apollo as Adapter

* feat: support apollo as Adapter

* feat: support apollo as Adapter

* feat: test apollo Adapter

* feat: test apollo Adapter

Co-authored-by: hongyihui <hongyihui@lixiang.com>
Co-authored-by: houseme <housemecn@gmail.com>
Co-authored-by: John Guo <john@johng.cn>

* add gcfg.Adapter implements using apollo service

* ci yaml update for apollo

Co-authored-by: hong0220 <hong0220@users.noreply.github.com>
Co-authored-by: hongyihui <hongyihui@lixiang.com>
Co-authored-by: houseme <housemecn@gmail.com>
2022-09-30 18:19:52 +08:00
d9be1d0b52 add watch feature for package kubecm (#2164)
* version updates

* up

* add watch feature for package kubecm
2022-09-30 17:36:40 +08:00
6cd84e8276 fix configuration management for package gdb (#2163) 2022-09-30 15:41:51 +08:00
ceaeceadd9 add local db configuration support for package gdb (#2161)
* version updates

* add local db configuration support for package gdb

* add local db configuration support for package gdb

* add local db configuration support for package gdb
2022-09-29 11:58:03 +08:00
cd5bf7c504 Feature/driver-dm fix something is invalid in dm (#2158)
* fix core.hasfield error index out of range & fix GroupConcat is invalid in dm

* add unit test

Co-authored-by: Xu <zhenghao.xu>
2022-09-28 10:02:48 +08:00
66aa0c7050 add switch of brief stack for package gerror (#2153) 2022-09-27 10:11:33 +08:00
141ca62c6d feature/v2.2.0 (#2154) 2022-09-26 22:11:13 +08:00
9dc97f4b0d fix issue in init context for package gctx (#2138)
* fix issue in init context for package gctx

* improve package gtest
2022-09-23 20:50:48 +08:00
714bda3e0f remove noisy internal logging content of package gcron (#2141) 2022-09-23 20:50:25 +08:00
2b4598f65b fix: pgsql DoExec Transaction checks (#2101)
Co-authored-by: John Guo <john@johng.cn>
2022-09-20 20:29:42 +08:00
5e9ef8ada4 fix issue incorrect struct name match pattern for command gen service (#2125)
* project template update for command init

* improve command , add extra option 

* add  option for command

* up
2022-09-15 14:44:24 +08:00
cf7c07cc34 improve and add clear option for command gen dao/service (#2123)
* project template update for command init

* improve command , add extra option 

* add  option for command
2022-09-14 21:01:57 +08:00
508062f8dc fix issue bot :ignore issue which without labels (#2077)
Co-authored-by: John Guo <john@johng.cn>
2022-09-14 15:44:54 +08:00
e5c63c7e16 project template update for command init (#2117) 2022-09-11 20:02:28 +08:00
7a11f00eb4 TplTableNameCamelLowerCase remove space (#2109)
Co-authored-by: zengjia <zengjia2@37.com>
Co-authored-by: houseme <housemecn@gmail.com>
2022-09-11 20:02:07 +08:00
faf09c586c add GzipPathWriter for package gcompress (#2116)
* add GzipPathWriter for package gcompress

* UT case updates for package package gclient
2022-09-08 17:32:21 +08:00
c866b5005f fix error message for package gtrace (#2103) 2022-08-31 19:53:21 +08:00
a0619f7ff0 remove uint repeat conversion (#2096)
Co-authored-by: houseme <housemecn@gmail.com>
2022-08-26 15:45:41 +08:00
37aee19bfa new release v2.1.4 (#2095)
v2.1.4
2022-08-26 15:05:45 +08:00
27609d8da8 fix issue #1921 (#2091)
* CI updates

* fix issue in OpenAPI json marshaling of embedded struct definition; improve command gen service

* improve logging content printing for internal log

* fix issue #1921
2022-08-26 14:30:49 +08:00
c083b333d8 fix field type check for package gdb (#2086)
* CI updates

* fix field type check for package gdb
2022-08-26 14:30:33 +08:00
ee376883d1 improve logging content printing for internal log (#2090)
* CI updates

* fix issue in OpenAPI json marshaling of embedded struct definition; improve command gen service

* improve logging content printing for internal log
2022-08-26 14:30:12 +08:00
98169784b1 fix issue in OpenAPI json marshaling of embedded struct definition; improve command gen service (#2089)
* CI updates

* fix issue in OpenAPI json marshaling of embedded struct definition; improve command gen service
2022-08-24 21:20:17 +08:00
9d1c6f2daa v2.1.3 release (#2084) 2022-08-22 14:40:36 +08:00
25d4ba320a improve command init: add go mod tidy for init project (#2083)
* CI updates

* improve command init
2022-08-22 14:31:35 +08:00
3988a7ff6b add more UT cases for package gview (#2072)
* CI updates

* add more UT cases for package gview
2022-08-18 21:06:20 +08:00
26e3c7aeb8 fix issue 1914 (#2075)
* CI updates

* fix issue #1914
2022-08-18 21:05:58 +08:00
eff46bd1db fix issue #2047 (#2069) 2022-08-16 20:46:22 +08:00
7a3176ea77 Fix name of issue CI (#2071)
CI updates
2022-08-16 20:41:54 +08:00
a656ad0941 add issue bot support (#2065) (#2066) 2022-08-15 21:52:33 +08:00
299573dd19 fixed inconsistent results when converting float64(NaN) to int/uint on multiple platforms (#2064) 2022-08-15 21:51:34 +08:00
43b84f4044 fix clickhouse in function TableFields when configuration using link (#2063) 2022-08-15 20:53:02 +08:00
897d6d9ad0 fix gctx init slice bounds out of range on ios platform (#2062) 2022-08-15 20:40:17 +08:00
e4c8cfc16b add interface DB.CheckLocalTypeForField for package gdb (#2059) 2022-08-11 21:47:35 +08:00
95888e0b77 add last insert id support for pgsql (#1994) 2022-08-09 19:45:05 +08:00
Gin
4ded89d453 improve gdb.CheckValueForLocalType for pgsql (#2040) 2022-08-08 19:56:06 +08:00
Gin
82a3391937 fix precision lost of int64 for package gcfg (#2044)
fix: gcfg lose precision

Co-authored-by: qinyuguang <qinyuguang@meican.com>
2022-08-03 21:50:17 +08:00
f580b7a488 improve header printing in json format for package glog; add golang v1.18 support for ci workflow (#2037) 2022-07-29 19:06:22 +08:00
9df0a9da0a fix issue #1648 (#2033) 2022-07-28 10:11:15 +08:00
6172862061 add MiddlewareJsonBody, improve error response handling for package ghttp (#2032) 2022-07-27 19:52:02 +08:00
1ae037f515 Update goai_path.go (#2029) 2022-07-26 22:48:40 +08:00
6f7cd96a7f feature: gen dao from tpl file path (#2021) 2022-07-25 20:55:48 +08:00
e00d3ff7ff fix issue in gstr.Nl2Br (#2028) 2022-07-25 20:54:42 +08:00
390b936153 fix gf-cli command 'gen dao' help infomation (#2022) 2022-07-25 19:43:47 +08:00
863bea1ad1 improve field type check from db to golang (#2023) 2022-07-22 16:44:24 +08:00
b7794a8783 use method name as its command name if no name defined in Meta of input struct for package gcmd (#2019) 2022-07-19 16:30:00 +08:00
bb3c51c6cc add interrupt for concurrent ci workflows(#2020) 2022-07-18 22:24:22 +08:00
c3c82cebd5 Feature/ci cache (#2010) 2022-07-18 16:02:21 +08:00
5d51e9fa2c improve package gerror, add HasCode/HasError function for package gerror (#2006) 2022-07-15 10:49:04 +08:00
2c70bb6a00 ci updates 2022-07-14 20:54:00 +08:00
98b2e8ab18 improve panic...recover of exit feature for package ghttp/gtimer/gfsnotify (#2000) 2022-07-13 20:20:38 +08:00
675ae9bade fix concurrent safety for package gdb (#1998) 2022-07-12 21:26:18 +08:00
3e7e8ba6f2 fix(gdb): panic when concurrent db config map read and write. (#1997) 2022-07-12 19:31:22 +08:00
f1766bdbdc add init ctx feature (#1995) 2022-07-12 19:27:42 +08:00
e3665cedaf new version v2.1.2 (#1993) 2022-07-12 14:08:19 +08:00
dd7caea910 fix UT issue for package gcron (#1992) 2022-07-12 09:55:46 +08:00
8ed57c6468 Improve the code coverage of the gtype module (#1975) 2022-07-11 21:29:32 +08:00
0e6becc36d Improve the code coverage of the gvar module (#1982) 2022-07-11 19:35:31 +08:00
e38c455252 Improve the code coverage of the gpool, gqueue, gring module (#1987) 2022-07-11 19:34:40 +08:00
4c1cf73005 Improve the code coverage of the gutil, grand module (#1989) 2022-07-11 19:33:59 +08:00
384fb3c4d5 fix go.sum of package contrib/drivers/pgsql (#1980) 2022-07-07 21:52:21 +08:00
afb90b0af3 Feature/pgsql add pgsql unit test (#1853) (#1973) 2022-07-07 21:42:20 +08:00
1530ffc926 Improve the code coverage of the gset module (#1977) 2022-07-07 21:28:23 +08:00
f876a56d2a some improves for ci yaml and package cmd/gf, database/gdb (#1972) 2022-07-07 21:16:26 +08:00
d26eadf5be gfcli: fix imports parse and update gofmt (#1979) 2022-07-07 20:57:20 +08:00
13fc0cb9eb feat: pgsql 字段类型 支持 数组类型 (#1881) 2022-07-06 21:06:20 +08:00
Gin
59b3f6e962 improve list tables for pgsql (#1790) 2022-07-06 20:05:12 +08:00
80442efe94 redis add sentinel slaveOnly filed (#1948) 2022-07-06 19:54:36 +08:00
ab929e465b update comment for ghttp.Request (#1968) 2022-07-06 19:48:43 +08:00
047c90466d improve UT for package gcron (#1966) 2022-07-04 21:18:20 +08:00
40e6b2b0f1 fix gf run custom arguments and gf gen dao specify config file path (#1879) 2022-07-04 21:01:55 +08:00
9159f00014 Fix goai repeat param (#1916) 2022-07-04 20:40:28 +08:00
59a9484970 gf gen service supports the generation of service files in the specified naming format (#1953) 2022-07-04 20:36:58 +08:00
8a853b1bb7 add file export (#1959) 2022-07-04 20:17:00 +08:00
2bcd6c4771 add full week/month name support for pattern, add seconds fix feature in some delay seconds for package gcron (#1960) 2022-07-01 09:53:01 +08:00
1acc1b8230 improve DeepCopy feature for bunch of components, especially the container and gtime (#1956) 2022-06-29 14:58:27 +08:00
2c169e2330 improve package glog; fix issue in package gtrace (#1952) 2022-06-28 15:47:16 +08:00
f57d71b6fa add cross building support for sqlite in command gen dao (#1944) 2022-06-27 11:09:55 +08:00
796bc008f8 improve configuration parsing for command gen dao (#1938) 2022-06-24 18:03:05 +08:00
d7faae0531 add gstr.IsGNUVersion (#1937) 2022-06-24 16:54:24 +08:00
f0511592b5 github.com/glebarez/go-sqlite (#1932) 2022-06-24 16:15:42 +08:00
68efab79ef improve command gen service 2022-06-24 15:35:16 +08:00
1ede8c77ba version updates 2022-06-24 15:21:36 +08:00
48f95d0009 fix issue in Response.WriteJson/Xml functions 2022-06-24 15:21:10 +08:00
0bb57b8989 go.sum update 2022-06-24 15:16:46 +08:00
0503c17867 feat/gfcli: replace gofmt&goimports with tools/imports (#1935) 2022-06-24 14:15:20 +08:00
19779cd342 Fix multiple gdb-group overrides (#1890)
Co-authored-by: longl <longlei@dealmap.cloud>
2022-06-23 21:30:29 +08:00
141f3512a9 fix glog bug (#1844) 2022-06-23 21:05:12 +08:00
3b9e5c71bf version updates 2022-06-21 21:52:54 +08:00
2bcee014f7 add tracing feature for package gproc (#1923) 2022-06-21 21:46:12 +08:00
f0568b4e22 Merge branch 'develop' 2022-06-21 19:08:36 +08:00
8670f29c4e update project templates and improve command init for cli 2022-06-21 18:08:11 +08:00
33a528af76 fix issue #1913 2022-06-20 22:03:19 +08:00
52056644d4 add context parameter (#1919) 2022-06-20 20:34:59 +08:00
3ae23df4b3 Improve the code coverage of the gmap module (#1910) 2022-06-20 19:05:47 +08:00
1b327b8abd improve database configuration parsing for package gins/gdb 2022-06-20 12:07:51 +08:00
bb5cd3e224 fix database configuration parsing for package gins 2022-06-20 11:14:13 +08:00
1e8237446e add tracing logging content if trace id is available in context for package gcmd 2022-06-17 17:42:49 +08:00
b2b2044786 add tracing logging content if trace id is available in context for package gcmd 2022-06-17 17:41:10 +08:00
64c5222623 add environment support of opentelemetry propagation for package gctx 2022-06-17 16:47:01 +08:00
1597291ac3 improve configuration parsing for package gdb 2022-06-17 15:35:55 +08:00
c2e742335b add otel support for package gcmd 2022-06-17 15:16:35 +08:00
cf5884bc60 add SetBodyContent for gclient.Response 2022-06-17 11:31:32 +08:00
cbf5ee9649 go fmt -w 2022-06-16 18:02:51 +08:00
8ac177a6de improve UT for package gredis 2022-06-16 17:41:15 +08:00
cdd4473df5 improve command gen service; add error trace for error of some packages 2022-06-16 17:07:25 +08:00
aaebaa7250 improve DoRequestObj for gclient.Client 2022-06-16 10:51:12 +08:00
7443a8baa1 Merge branch 'develop' 2022-06-15 21:43:04 +08:00
c6ff95a3f4 README update for contrib/registry etcd/polaris 2022-06-15 21:42:12 +08:00
7957016ae2 Polaris Server Offical image support (#1911) 2022-06-15 19:38:22 +08:00
17ab0e2ced remove returning error of Write* functions for ghttp.Server; add UT cases for gclient.Client.DoRequestObj 2022-06-15 19:36:53 +08:00
b0650f3402 Improve the code coverage of the garray,glist module (#1908) 2022-06-15 19:35:21 +08:00
f4f73f2765 Merge branch 'master' of https://github.com/gogf/gf into develop 2022-06-15 16:28:20 +08:00
babc69e13d add DoRequestObj function for gclient.Client 2022-06-15 16:28:17 +08:00
481c50f233 add example for package gerror 2022-06-15 14:46:31 +08:00
b62b2f3598 Improve the code coverage of the gudp module (#1907) 2022-06-13 22:01:20 +08:00
4f37abac6a upgrade ClickHouse-Go dependencies to V2.0.15 (#1904) 2022-06-13 19:40:47 +08:00
31a23e724d Improve the code coverage of the gclient module (#1899) 2022-06-13 19:31:42 +08:00
7d5ab1f8db Merge branch 'master' of https://github.com/gogf/gf 2022-06-06 21:36:44 +08:00
0d8952dcde improve WithTraceID function for package gtrace 2022-06-06 21:36:30 +08:00
bd7ec5d0b0 Feature/sqlite ut (#1882) 2022-06-06 19:57:53 +08:00
MZ
9e6e8001ca fix gf gen service ignore watch file dir windows platform bug (#1889) 2022-06-06 19:56:44 +08:00
0639becccc version updates 2022-06-01 16:36:40 +08:00
88844649eb fix version of redoc 2022-06-01 16:34:07 +08:00
31c5d5a5f5 Merge branch 'master' of https://github.com/gogf/gf into develop 2022-06-01 14:44:11 +08:00
6abbc57c96 fix issue #1864 2022-05-26 15:28:17 +08:00
39af6e51c4 fix ut cases for package goai 2022-05-26 15:17:59 +08:00
ef04c8a09e Feature/oracle (#1869) 2022-05-25 21:55:27 +08:00
4505d61604 improve WhereBuilder feature for package gdb 2022-05-25 21:52:08 +08:00
04d32e7a91 improve FieldsPrefix for gdb.Model 2022-05-25 16:22:46 +08:00
26066965c3 Merge branch 'master' of https://github.com/gogf/gf into develop 2022-05-25 16:02:48 +08:00
7f199527f8 improve service discovery for package gclient 2022-05-24 19:16:43 +08:00
ea79b3cbb8 move package goai from protocol to net 2022-05-24 18:53:10 +08:00
0ca81bd11a Improve the code coverage of the gtcp module (#1836) 2022-05-23 22:45:12 +08:00
4d13ffdc26 improve ut case for empty upload file validation 2022-05-23 22:23:29 +08:00
331a29024e merge master 2022-05-23 22:17:06 +08:00
6aa5c2b2ef Fix/1748 issues #1748 (#1817) 2022-05-23 22:09:11 +08:00
8c969b2a84 upgrade ClickHouse dependencies to V2 (#1772) 2022-05-23 21:21:59 +08:00
0d7e28ee75 add deep copy feature 2022-05-23 16:51:10 +08:00
ab5062663e Feature/gsvc interface (#1871) 2022-05-23 15:08:11 +08:00
896b9fa105 [ISSUE #1866] Fix/polaris logs dir and docker image (#1867)
* feat:modify polaris log dir

* modify polaris image docker

* fix: modify polaris docker image
2022-05-19 23:33:04 +08:00
6a01275499 improve data converting for package gdb 2022-05-19 21:44:53 +08:00
61bf0a0092 remove sqlite import for command gen dao 2022-05-19 20:13:56 +08:00
d7c5a08d20 fix issue of space char in binary pth of gofmt/goimports 2022-05-19 20:03:44 +08:00
350ee9f0a2 ci workflow updates 2022-05-19 19:59:41 +08:00
7753fc6fe1 improve error message for package gdb 2022-05-19 17:27:13 +08:00
24f5b2782d version updates 2022-05-19 16:10:52 +08:00
853d7aaf8f fix issue missing mysql driver import for package contrib/drivers/mysql 2022-05-19 15:02:15 +08:00
07509e9847 go mod tidy 2022-05-19 10:49:09 +08:00
ab82599ee2 Feature/polaris feat: Add Polaris support (#1797) 2022-05-18 22:24:40 +08:00
10e2b60ad9 workflow ci updates 2022-05-18 21:38:13 +08:00
965476c7f4 workflow ci updates 2022-05-18 21:24:15 +08:00
9536b33a6a Fix/codecovci (#1858) 2022-05-18 21:18:49 +08:00
61271e4f7b Replace the Swagger JS CDN source from jsdelivr to unpkg.com (#1852)
replace the CDN source from jsdelivr to unpkg.com

The jsdelivr cdn certificate expired in the mainland, causing the website to hang. To fix it, the solution is to replace the CDN source to unpkg.com
2022-05-18 20:34:59 +08:00
57941b6df9 Bug fix#1849 (#1851) 2022-05-18 20:19:40 +08:00
1102de5a66 fix issue in missing mysql import for command gen dao 2022-05-18 20:02:53 +08:00
6d33a73617 Merge branch 'master' of https://github.com/gogf/gf 2022-05-18 19:58:25 +08:00
cdcb0cdc14 Merge branch 'develop' 2022-05-18 19:58:16 +08:00
6176028176 improve package gmeta 2022-05-18 17:57:16 +08:00
c871bb3a1e improve package gcfg 2022-05-18 15:11:49 +08:00
3430cf1f17 improve data converting for package gdb, drivers/pgsql 2022-05-18 11:55:09 +08:00
4556dda038 improve data converting for package gdb, drivers/pgsql 2022-05-18 11:16:25 +08:00
49042d480c improve data converting for package gdb, drivers/pgsql 2022-05-18 11:05:05 +08:00
b7295a1558 Merge pull request #1843 from wenzi1/feature/mssql
mssql unit test
2022-05-17 21:24:50 +08:00
62d91438f2 version upgrade 2022-05-17 16:43:10 +08:00
c4c3620c5f improve enum handling for array property of goai schema 2022-05-17 11:15:29 +08:00
ec0cbab47e Merge remote-tracking branch 'origin/master' into feature/mssql 2022-05-17 09:42:21 +08:00
8e3c66584d add unit test 2022-05-16 22:58:53 +08:00
84e75129a5 improve command gen service for cli 2022-05-16 20:07:30 +08:00
26d460241d Null in field is error 2022-05-13 23:30:33 +08:00
ede54b392e Merge branch 'master' of https://github.com/wenzi1/gf 2022-05-13 23:13:07 +08:00
d12542d78e Merge remote-tracking branch 'origin/master' 2022-05-13 22:20:50 +08:00
3a014dcb09 fix issue in UT of mysql sriver 2022-05-13 22:11:44 +08:00
cb27f26e64 Merge branch 'gogf:master' into master 2022-05-13 22:00:49 +08:00
a3ad294d6a README updates for drivers 2022-05-13 21:54:24 +08:00
cf57ea3ef0 Merge branch 'gogf:master' into master 2022-05-13 21:51:08 +08:00
94dd590fc4 Merge branch 'develop' 2022-05-13 21:48:11 +08:00
27836feb47 delete comment 2022-05-13 21:45:19 +08:00
96e48e1de6 Merge branch 'master' into feature/mssql 2022-05-13 21:07:34 +08:00
d5c06664b5 fix issue #1798 2022-05-13 21:04:08 +08:00
e4edbe25b2 Merge pull request #1823 from huangqian1985/master
add gClient ExampleNew function
2022-05-13 20:24:19 +08:00
31bc30bb27 Merge pull request #1806 from happyinsect/master
add support for .properties configuration file
2022-05-13 20:01:29 +08:00
a2905977ec improve package gcmd, adding CaseSensitive option for options parsing, default is CaseInsensitive 2022-05-13 15:24:10 +08:00
b63e01adf6 add internal log content for package gcmd 2022-05-13 14:48:22 +08:00
2680666f52 improve gstr.WordWrap 2022-05-13 14:18:51 +08:00
f82f53f5f6 modify ExampleNew_MultiConn_Recommend function 2022-05-13 11:58:46 +08:00
e27ca17b0e exec CI 2022-05-13 06:47:48 +08:00
066b1026a2 Merge branch 'master' of https://github.com/gogf/gf 2022-05-12 23:46:31 +08:00
c7cf72e7bc fix gClien Close() 2022-05-12 23:22:30 +08:00
0e2a0075ef Use gconv.String instead of cast.ToString. 2022-05-12 22:59:08 +08:00
6dccaf802c CI updates 2022-05-12 22:45:57 +08:00
de5224689a CI updates 2022-05-12 22:26:57 +08:00
f9ec01c647 CI workflow updates 2022-05-12 21:57:02 +08:00
4902eb73b7 gfmt file 2022-05-12 21:31:54 +08:00
513c8605fb update go.mod and go.sum 2022-05-12 21:11:06 +08:00
84148bbbb0 Merge https://github.com/gogf/gf 2022-05-12 20:57:11 +08:00
c2e91edca8 Merge branch 'master' of https://github.com/gogf/gf 2022-05-12 20:17:08 +08:00
17fc1ce174 Call ReadAll() function in Close() of gClient 2022-05-12 20:08:24 +08:00
be9377a496 add test cases 2022-05-12 17:05:02 +08:00
c40a4d8a66 improve command docker for cli 2022-05-12 17:04:00 +08:00
6d0b4faeb0 gitignore updates 2022-05-12 16:01:55 +08:00
3297924992 ci test 2022-05-12 15:33:48 +08:00
059c62a6c0 ci test 2022-05-12 15:25:28 +08:00
bef942b19f ci test 2022-05-12 14:57:26 +08:00
30140fb229 ci test 2022-05-12 14:37:31 +08:00
df3ae386cb ci test 2022-05-12 14:35:39 +08:00
baf4cc1d1c remove bad example and little fix 2022-05-12 12:48:37 +08:00
9fcd3374c1 Merge pull request #1827 from wenzi1/feature/mssql
Feature/mssql
2022-05-12 11:47:28 +08:00
d5d56e51d7 增加用例覆盖率 2022-05-12 09:39:15 +08:00
3b8853736d Merge branch 'develop' into master 2022-05-12 09:25:25 +08:00
16b22e7505 add unit test 2022-05-12 09:03:55 +08:00
da7eac03ad delete package comment 2022-05-12 00:25:30 +08:00
060f67c2c8 change decode/encode lib for properties to magiconair 2022-05-12 00:23:46 +08:00
273b81d60f little fix 2022-05-12 00:22:10 +08:00
72b58ff8a1 add unit test 2022-05-12 00:03:20 +08:00
900e0b2751 add gini 2022-05-12 00:00:36 +08:00
9026fd2c13 add gClient ExampleNew function, include normal New Example, bad MultiConn New Example and Recommend MultiConn New Example 2022-05-11 23:58:36 +08:00
f6f0c8fd1e ci test 2022-05-11 20:42:34 +08:00
4bdaacab91 ci test 2022-05-11 20:12:30 +08:00
60ca7d7246 ci test 2022-05-11 18:11:35 +08:00
e4e312c4f8 ci updates 2022-05-11 17:51:27 +08:00
7bcdbae7b8 ci updates 2022-05-11 17:36:55 +08:00
b16cd2dc85 ci updates 2022-05-11 17:11:18 +08:00
0826f8ba35 Merge pull request #1818 from wenzi1/master
gf-cli Bug of generating Dao file of MSSQL
2022-05-11 13:58:47 +08:00
ead284e20b workflow updates 2022-05-11 13:58:04 +08:00
59023f9f09 delete empty line after package comment. 2022-05-11 11:08:05 +08:00
17e48ba9f2 Add test case for func tojson 2022-05-11 01:02:36 +08:00
e60b42470e [MOD] User viper as the properties file decoding lib. 2022-05-11 00:48:22 +08:00
9c42ba187d upgrade otel to v1.7.0 2022-05-10 20:37:44 +08:00
c6f14dc1b1 go mod updates 2022-05-10 17:54:42 +08:00
02e3240bb1 workflow yaml updates 2022-05-10 17:16:39 +08:00
54f0968f86 workflow yaml updates 2022-05-10 16:53:39 +08:00
0e75d39811 workflow yaml updates 2022-05-10 16:34:47 +08:00
6cf6414da2 improve package gdb 2022-05-10 16:31:56 +08:00
89f77a2412 update TableFields function 2022-05-10 16:00:50 +08:00
a400d8b2f3 workflow updates 2022-05-10 15:47:49 +08:00
dc6a9237d7 move ut cases from package gdb to contrib/drivers/mysql 2022-05-10 15:38:08 +08:00
2c73ba2f76 Merge pull request #2 from gogf/master
update
2022-05-10 10:37:13 +08:00
2cbfdf43cf upgrade used third party package fsnotify to v1.5.4 2022-05-10 10:23:31 +08:00
5e0e6f356b fix issue #1766 2022-05-09 22:47:04 +08:00
cbff244d88 improve package gcron 2022-05-09 21:45:57 +08:00
2e405342ca improve package gcron 2022-05-09 21:42:50 +08:00
583d576cdb remove octal number converting for gconv.Int*/Uint* functions; fix issue #1733 2022-05-09 21:26:42 +08:00
3db97ba0dd fix issue #1714, #1727 2022-05-09 20:42:41 +08:00
e81d6a859b Merge pull request #1729 from WesleyWu/fix#1714
fix timezone bug when persisting *gtime.Time to db #1714
2022-05-09 20:28:00 +08:00
534abb7f17 improve hook feature for package gdb 2022-05-09 14:22:28 +08:00
7198eb3b66 add support for .properties configuration file 2022-05-08 00:23:24 +08:00
32f33b9f8c go.mod updates 2022-05-07 18:06:51 +08:00
03ad6a5728 remove debug info for UT of package gdb 2022-05-07 17:50:49 +08:00
c1308475f3 Merge branch 'feature/wherebuilder' into develop 2022-05-07 17:49:30 +08:00
e4ec1be948 workflow updates 2022-05-07 16:43:28 +08:00
c90f91dcbe remove Sharding feature 2022-05-07 16:38:17 +08:00
5332ce4c79 improve WhereBuilder feature for package gdb 2022-05-07 15:11:31 +08:00
eaae7f46d2 improve WhereBuilder feature for package gdb 2022-05-07 14:26:56 +08:00
8c40a53b80 improve WhereBuilder for package gdb 2022-05-06 22:21:43 +08:00
25c091df7f improve package ghttp 2022-05-06 20:25:21 +08:00
ec3a4532b8 comment updates for package clilckhouse 2022-05-06 10:34:08 +08:00
ad04adccea Merge pull request #1796 from houseme/feature/trace
feat: Report trace-compatible device host name or IP archive parameters
2022-05-05 22:19:35 +08:00
cfd2636f13 Merge pull request #1795 from huangqian1985/master
add ExampleEncode function
2022-05-05 22:18:20 +08:00
7e854f88ca feat: Report trace-compatible device host name or IP archive parameters 2022-05-03 22:53:02 +08:00
3628b1e9d2 add ExampleEncode function 2022-05-02 17:29:19 +08:00
68e75c589b add WhereBuilder feature for package gdb 2022-04-30 15:53:56 +08:00
9ad9292321 improve handler feature for package glog 2022-04-29 14:13:54 +08:00
7fcf7d31a0 improve command gen service for cli 2022-04-29 11:08:16 +08:00
0cf28c0f07 improve package goai 2022-04-28 20:58:28 +08:00
abbc96a873 improve package goai 2022-04-28 20:37:15 +08:00
b7201e111d Merge branch 'master' of https://github.com/gogf/gf into develop 2022-04-28 20:34:35 +08:00
a31553468c Merge pull request #1789 from mingzaily/master
fix: swagger ignore "-" param.
2022-04-28 20:24:11 +08:00
ce89b440bb feat: optimize ignore tag. 2022-04-28 17:14:19 +08:00
3a72c4a507 improve command gen service for cli 2022-04-28 15:09:54 +08:00
c82e612258 improve command gen service for cli 2022-04-27 22:10:49 +08:00
ae5891068e schema switch in runtime feature for clickhouse/mssql/pgsql/oracle 2022-04-27 17:15:26 +08:00
f326dc4eaa remove unused imports for package gdb 2022-04-27 15:27:44 +08:00
48fddcd5e7 improve session Manager and default Storage implements for package gsession; fix issue #1781 2022-04-27 15:05:34 +08:00
33c9204d58 fix: swagger ignore "-" param. 2022-04-26 23:22:43 +08:00
99f1e69469 add custom dao/do/entity path support for command gen dao for cli 2022-04-26 23:18:29 +08:00
ed0b3c039a improve package gsession; improve command docker for cli 2022-04-26 22:42:56 +08:00
eef25c28b4 improve command docker/gen service 2022-04-26 17:49:01 +08:00
a32847f0c5 add default handler feature for package glog 2022-04-25 18:05:52 +08:00
0fc193faa3 add command gen service for cli 2022-04-24 22:52:29 +08:00
65077a224c add command gen service for cli 2022-04-24 22:52:07 +08:00
c256d2d4af fix issue in gstr.RepliaceI; add command gen service for cli 2022-04-24 22:23:56 +08:00
215a50675e add command gen service for cli 2022-04-22 18:17:10 +08:00
023c4a19ae add multiple tags support for command docker of cli 2022-04-21 15:29:10 +08:00
ac5d399906 improve package guid 2022-04-19 16:18:49 +08:00
7fd0e5b3bc fix issue in loosing internal ctx data in cache feature for package gdb 2022-04-19 10:42:16 +08:00
64ff651d57 fix issue in loosing internal ctx data for Transaction for package gdb; fix issue #1732 2022-04-19 10:22:10 +08:00
d260de15ba fix issue #1750 2022-04-18 20:57:41 +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
1a271ce627 fix timezone bug when persisting *gtime.Time to db #1714 2022-04-03 16:00:19 +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
c7f51b8e77 fix: SetListener test data race error 2022-03-30 14:55:03 +08:00
b57cbacc82 refactor: method SetListener accepts slice of net.Listener and remove method SetListeners 2022-03-29 23:22:23 +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
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
d7bd1b74e8 feat: support custom listener 2022-03-18 20:54:32 +08:00
5e3c0bd9aa improve clickhouse driver 2022-02-24 21:06:26 +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
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
61c9d5fb3f Merge pull request #1 from gogf/master
是是是
2022-01-05 19:14:33 +08:00
656 changed files with 43619 additions and 9404 deletions

View File

@ -0,0 +1,42 @@
version: '2'
services:
apollo-quick-start:
image: "loads/apollo-quick-start:latest"
container_name: apollo-quick-start
depends_on:
- apollo-db
ports:
- "8080:8080"
- "8070:8070"
- "8060:8060"
links:
- apollo-db
#environment:
#JAVA_OPTS: '-Xms100m -Xmx1000m -Xmn100m -Xss256k -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=250m'
#APOLLO_CONFIG_DB_USERNAME: 'root'
#APOLLO_CONFIG_DB_PASSWORD: 'apollo'
#APOLLO_PORTAL_DB_USERNAME: 'root'
#APOLLO_PORTAL_DB_PASSWORD: 'apollo'
apollo-db:
image: "loads/mysql:5.7"
container_name: apollo-db
environment:
TZ: Asia/Shanghai
MYSQL_ALLOW_EMPTY_PASSWORD: 'yes'
#MYSQL_ROOT_PASSWORD: 'apollo'
depends_on:
- apollo-dbdata
ports:
- "13306:3306"
volumes:
- ./sql:/docker-entrypoint-initdb.d
volumes_from:
- apollo-dbdata
apollo-dbdata:
image: "loads/alpine:3.8"
container_name: apollo-dbdata
volumes:
- /var/lib/mysql

View File

@ -0,0 +1,467 @@
--
-- Copyright 2022 Apollo Authors
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Create Database
# ------------------------------------------------------------
CREATE DATABASE IF NOT EXISTS ApolloConfigDB DEFAULT CHARACTER SET = utf8mb4;
Use ApolloConfigDB;
# Dump of table app
# ------------------------------------------------------------
DROP TABLE IF EXISTS `App`;
CREATE TABLE `App` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
`OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
`OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
`OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
`OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Name` (`Name`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';
# Dump of table appnamespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `AppNamespace`;
CREATE TABLE `AppNamespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字注意需要全局唯一',
`AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id',
`Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型',
`IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共',
`Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`),
KEY `Name_AppId` (`Name`,`AppId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义';
# Dump of table audit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Audit`;
CREATE TABLE `Audit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名',
`EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID',
`OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表';
# Dump of table cluster
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Cluster`;
CREATE TABLE `Cluster` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字',
`AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id',
`ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`),
KEY `IX_ParentClusterId` (`ParentClusterId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群';
# Dump of table commit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Commit`;
CREATE TABLE `Commit` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`ChangeSets` longtext NOT NULL COMMENT '修改变更集',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Comment` varchar(500) DEFAULT NULL COMMENT '备注',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `AppId` (`AppId`(191)),
KEY `ClusterName` (`ClusterName`(191)),
KEY `NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表';
# Dump of table grayreleaserule
# ------------------------------------------------------------
DROP TABLE IF EXISTS `GrayReleaseRule`;
CREATE TABLE `GrayReleaseRule` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name',
`Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release',
`BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2全量发布',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表';
# Dump of table instance
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Instance`;
CREATE TABLE `Instance` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name',
`Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`),
KEY `IX_IP` (`Ip`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例';
# Dump of table instanceconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `InstanceConfig`;
CREATE TABLE `InstanceConfig` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id',
`ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id',
`ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name',
`ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`),
KEY `IX_ReleaseKey` (`ReleaseKey`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息';
# Dump of table item
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Item`;
CREATE TABLE `Item` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Value` longtext NOT NULL COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_GroupId` (`NamespaceId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目';
# Dump of table namespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Namespace`;
CREATE TABLE `Namespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191),`DeletedAt`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_NamespaceName` (`NamespaceName`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间';
# Dump of table namespacelock
# ------------------------------------------------------------
DROP TABLE IF EXISTS `NamespaceLock`;
CREATE TABLE `NamespaceLock` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
`NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
`IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁';
# Dump of table release
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Release`;
CREATE TABLE `Release` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key',
`Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字',
`Comment` varchar(256) DEFAULT NULL COMMENT '发布说明',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`Configurations` longtext NOT NULL COMMENT '发布配置',
`IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`),
KEY `AppId_ClusterName_GroupName` (`AppId`(191),`ClusterName`(191),`NamespaceName`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布';
# Dump of table releasehistory
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseHistory`;
CREATE TABLE `ReleaseHistory` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName',
`NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName',
`BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名',
`ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id',
`PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId',
`Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型0: 普通发布1: 回滚2: 灰度发布3: 灰度规则更新4: 灰度合并回主分支发布5: 主分支发布灰度自动发布6: 主分支回滚灰度自动发布7: 放弃灰度',
`OperationContext` longtext NOT NULL COMMENT '发布上下文信息',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`),
KEY `IX_ReleaseId` (`ReleaseId`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史';
# Dump of table releasemessage
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ReleaseMessage`;
CREATE TABLE `ReleaseMessage` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Message` (`Message`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息';
# Dump of table serverconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ServerConfig`;
CREATE TABLE `ServerConfig` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群default为不针对特定的集群',
`Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置';
# Dump of table accesskey
# ------------------------------------------------------------
DROP TABLE IF EXISTS `AccessKey`;
CREATE TABLE `AccessKey` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret',
`IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥';
# Config
# ------------------------------------------------------------
INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`)
VALUES
('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url多个service以英文逗号分隔'),
('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'),
('item.value.length.limit', 'default', '20000', 'item value最大长度限制'),
('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存开启后能提高性能但是会增大内存消耗'),
('item.key.length.limit', 'default', '128', 'item key 最大长度限制');
# Sample Data
# ------------------------------------------------------------
INSERT INTO `App` (`AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`)
VALUES
('SampleApp', 'Sample App', 'TEST1', '样例部门1', 'apollo', 'apollo@acme.com');
INSERT INTO `AppNamespace` (`Name`, `AppId`, `Format`, `IsPublic`, `Comment`)
VALUES
('application', 'SampleApp', 'properties', 0, 'default app namespace');
INSERT INTO `Cluster` (`Name`, `AppId`)
VALUES
('default', 'SampleApp');
INSERT INTO `Namespace` (`Id`, `AppId`, `ClusterName`, `NamespaceName`)
VALUES
(1, 'SampleApp', 'default', 'application');
INSERT INTO `Item` VALUES (1,1,'timeout','100','sample timeout配置',1,_binary '\0',0,'default','2022-09-28 15:43:17','','2022-09-28 15:43:17'),
(2,1,'','','',2,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(3,1,'server.address',':8000','',3,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(4,1,'server.dumpRouterMap','true','',4,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(5,1,'server.routeOverWrite','true','',5,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(6,1,'server.accessLogEnabled','true','',6,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(7,1,'server.openapiPath','/api.json','',7,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(8,1,'server.swaggerPath','/swagger','',8,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(9,1,'','','',9,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(10,1,'','','# Global logging.',10,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(11,1,'logger.level','all','',11,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55'),
(12,1,'logger.stdout','true','',12,_binary '\0',0,'apollo','2022-09-28 15:47:55','apollo','2022-09-28 15:47:55');
INSERT INTO `Release` VALUES (1,'20161009155425-d3a0749c6e20bc15','20161009155424-release','Sample发布','SampleApp','default','application','{\"timeout\":\"100\"}',_binary '\0',_binary '\0',0,'default','2022-09-28 15:59:38','','2022-09-28 15:59:38'),
(2,'20220929000151-1dc5634459e19171','20220929000148-release','','SampleApp','default','application','{\"timeout\":\"100\",\"server.address\":\":8000\",\"server.dumpRouterMap\":\"true\",\"server.routeOverWrite\":\"true\",\"server.accessLogEnabled\":\"true\",\"server.openapiPath\":\"/api.json\",\"server.swaggerPath\":\"/swagger\",\"logger.level\":\"all\",\"logger.stdout\":\"true\"}',_binary '\0',_binary '\0',0,'apollo','2022-09-28 16:01:51','apollo','2022-09-28 16:01:51');
INSERT INTO `ReleaseHistory` VALUES (1,'SampleApp','default','application','default',1,0,0,'{}',_binary '\0',0,'apollo','2022-09-28 15:59:38','apollo','2022-09-28 15:59:38'),
(2,'SampleApp','default','application','default',2,1,0,'{\"isEmergencyPublish\":false}',_binary '\0',0,'apollo','2022-09-28 16:01:51','apollo','2022-09-28 16:01:51');
INSERT INTO `ReleaseMessage` VALUES (1,'SampleApp+default+application','2022-09-28 15:59:38'),
(2,'SampleApp+default+application','2022-09-28 16:01:51');
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

View File

@ -0,0 +1,420 @@
--
-- Copyright 2022 Apollo Authors
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
# Create Database
# ------------------------------------------------------------
CREATE DATABASE IF NOT EXISTS ApolloPortalDB DEFAULT CHARACTER SET = utf8mb4;
Use ApolloPortalDB;
# Dump of table app
# ------------------------------------------------------------
DROP TABLE IF EXISTS `App`;
CREATE TABLE `App` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
`OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
`OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
`OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
`OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`),
KEY `DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_Name` (`Name`(191))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表';
# Dump of table appnamespace
# ------------------------------------------------------------
DROP TABLE IF EXISTS `AppNamespace`;
CREATE TABLE `AppNamespace` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字注意需要全局唯一',
`AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id',
`Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型',
`IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共',
`Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`),
KEY `Name_AppId` (`Name`,`AppId`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义';
# Dump of table consumer
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Consumer`;
CREATE TABLE `Consumer` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名',
`OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id',
`OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字',
`OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName',
`OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者';
# Dump of table consumeraudit
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ConsumerAudit`;
CREATE TABLE `ConsumerAudit` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id',
`Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri',
`Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_ConsumerId` (`ConsumerId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表';
# Dump of table consumerrole
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ConsumerRole`;
CREATE TABLE `ConsumerRole` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id',
`RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_RoleId` (`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表';
# Dump of table consumertoken
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ConsumerToken`;
CREATE TABLE `ConsumerToken` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId',
`Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token',
`Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表';
# Dump of table favorite
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Favorite`;
CREATE TABLE `Favorite` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户',
`AppId` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'AppID',
`Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`),
KEY `AppId` (`AppId`(191)),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表';
# Dump of table permission
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Permission`;
CREATE TABLE `Permission` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型',
`TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表';
# Dump of table role
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Role`;
CREATE TABLE `Role` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
# Dump of table rolepermission
# ------------------------------------------------------------
DROP TABLE IF EXISTS `RolePermission`;
CREATE TABLE `RolePermission` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id',
`PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_PermissionId` (`PermissionId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表';
# Dump of table serverconfig
# ------------------------------------------------------------
DROP TABLE IF EXISTS `ServerConfig`;
CREATE TABLE `ServerConfig` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key',
`Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值',
`Comment` varchar(1024) DEFAULT '' COMMENT '注释',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`),
KEY `DataChange_LastTime` (`DataChange_LastTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置';
# Dump of table userrole
# ------------------------------------------------------------
DROP TABLE IF EXISTS `UserRole`;
CREATE TABLE `UserRole` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识',
`RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id',
`IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal',
`DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds',
`DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀',
`DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀',
`DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`),
KEY `IX_DataChange_LastTime` (`DataChange_LastTime`),
KEY `IX_RoleId` (`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表';
# Dump of table Users
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Users`;
CREATE TABLE `Users` (
`Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户',
`Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码',
`UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称',
`Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址',
`Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效',
PRIMARY KEY (`Id`),
UNIQUE KEY `UK_Username` (`Username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
# Dump of table Authorities
# ------------------------------------------------------------
DROP TABLE IF EXISTS `Authorities`;
CREATE TABLE `Authorities` (
`Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id',
`Username` varchar(64) NOT NULL,
`Authority` varchar(50) NOT NULL,
PRIMARY KEY (`Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
# Config
# ------------------------------------------------------------
INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`)
VALUES
('apollo.portal.envs', 'dev', '可支持的环境列表'),
('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'),
('superAdmin', 'apollo', 'Portal超级管理员'),
('api.readTimeout', '10000', 'http接口read timeout'),
('consumer.token.salt', 'someSalt', 'consumer token salt'),
('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'),
('configView.memberOnly.envs', 'dev', '只对项目成员显示配置信息的环境列表多个env以英文逗号分隔'),
('apollo.portal.meta.servers', '{}', '各环境Meta Service列表');
INSERT INTO `Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`)
VALUES
('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1);
INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user');
# Sample Data
# ------------------------------------------------------------
INSERT INTO `App` (`AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`)
VALUES
('SampleApp', 'Sample App', 'TEST1', '样例部门1', 'apollo', 'apollo@acme.com');
INSERT INTO `AppNamespace` (`Name`, `AppId`, `Format`, `IsPublic`, `Comment`)
VALUES
('application', 'SampleApp', 'properties', 0, 'default app namespace');
INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`)
VALUES
(1, 'CreateCluster', 'SampleApp'),
(2, 'CreateNamespace', 'SampleApp'),
(3, 'AssignRole', 'SampleApp'),
(4, 'ModifyNamespace', 'SampleApp+application'),
(5, 'ReleaseNamespace', 'SampleApp+application');
INSERT INTO `Role` (`Id`, `RoleName`)
VALUES
(1, 'Master+SampleApp'),
(2, 'ModifyNamespace+SampleApp+application'),
(3, 'ReleaseNamespace+SampleApp+application');
INSERT INTO `RolePermission` (`RoleId`, `PermissionId`)
VALUES
(1, 1),
(1, 2),
(1, 3),
(2, 4),
(3, 5);
INSERT INTO `UserRole` (`UserId`, `RoleId`)
VALUES
('apollo', 1),
('apollo', 2),
('apollo', 3);
-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql)
CREATE TABLE SPRING_SESSION (
PRIMARY_ID CHAR(36) NOT NULL,
SESSION_ID CHAR(36) NOT NULL,
CREATION_TIME BIGINT NOT NULL,
LAST_ACCESS_TIME BIGINT NOT NULL,
MAX_INACTIVE_INTERVAL INT NOT NULL,
EXPIRY_TIME BIGINT NOT NULL,
PRINCIPAL_NAME VARCHAR(100),
CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID)
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID);
CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME);
CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME);
CREATE TABLE SPRING_SESSION_ATTRIBUTES (
SESSION_PRIMARY_ID CHAR(36) NOT NULL,
ATTRIBUTE_NAME VARCHAR(200) NOT NULL,
ATTRIBUTE_BYTES BLOB NOT NULL,
CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME),
CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE
) ENGINE=InnoDB ROW_FORMAT=DYNAMIC;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

6
.github/workflows/before_script.sh vendored Normal file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env bash
find . -name "*.go" | xargs gofmt -w
git diff --name-only --exit-code || if [ $? != 0 ]; then echo "Notice: gofmt check failed,please gofmt before pr." && exit 1; fi
echo "gofmt check pass."
sudo echo "127.0.0.1 local" | sudo tee -a /etc/hosts

40
.github/workflows/build_and_test.sh vendored Normal file
View File

@ -0,0 +1,40 @@
#!/usr/bin/env bash
GOARCH=${{ matrix.goarch }}
for file in `find . -name go.mod`; do
dirpath=$(dirname $file)
echo $dirpath
# package oracle needs golang >= v1.17
if [ "oracle" = $(basename $dirpath) ]; then
if ! go version|grep -q "1.17"; then
echo "ignore oracle as go version: $(go version)"
continue 1
fi
fi
# package kuhecm needs golang >= v1.18
if [ "kubecm" = $(basename $dirpath) ]; then
if ! go version|grep -q "1.18"; then
echo "ignore kubecm as go version: $(go version)"
continue 1
fi
fi
# package example needs golang >= v1.18
if [ "example" = $(basename $dirpath) ]; then
if ! go version|grep -q "1.18"; then
echo "ignore example as go version: $(go version)"
continue 1
fi
fi
cd $dirpath
go mod tidy
go build ./...
go test ./... -race -coverprofile=coverage.out -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1
if grep -q "/gogf/gf/.*/v2" go.mod; then
sed -i "s/gogf\/gf\(\/.*\)\/v2/gogf\/gf\/v2\1/g" coverage.out
fi
cd -
done

View File

@ -52,7 +52,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: GoFrame CLI Release ${{ github.ref }}
release_name: GoFrame Release ${{ github.ref }}
draft: false
prerelease: false

View File

@ -1,4 +1,4 @@
name: GoFrame CI
name: GoFrame Main CI
on:
@ -6,25 +6,38 @@ on:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
pull_request:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
env:
GF_DEBUG: 0
TZ: "Asia/Shanghai"
jobs:
code-test:
runs-on: ubuntu-latest
# Service containers to run with `code-test`
services:
# Redis backend server.
redis:
image : redis
image : loads/redis:latest
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
@ -34,8 +47,9 @@ jobs:
# Maps tcp port 6379 on service container to the host
- 6379:6379
# MySQL backend server.
mysql:
image: mysql:5.7
image: loads/mysql:5.7
env:
MYSQL_DATABASE : test
MYSQL_ROOT_PASSWORD: 12345678
@ -43,11 +57,13 @@ jobs:
# Maps tcp port 3306 on service container to the host
- 3306:3306
# PostgreSQL backend server.
# docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=12345678 -e POSTGRES_USER=postgres -e POSTGRES_DB=test -v postgres:/Users/john/Temp/postgresql/data loads/postgres:13
postgres:
image: postgres:13
image: loads/postgres:13
env:
POSTGRES_PASSWORD: 12345678
POSTGRES_USER: root
POSTGRES_USER: postgres
POSTGRES_DB: test
TZ: Asia/Shanghai
ports:
@ -59,8 +75,9 @@ jobs:
--health-timeout 5s
--health-retries 5
# MSSQL backend server.
mssql:
image: mcmoe/mssqldocker:latest
image: loads/mssqldocker:latest
env:
ACCEPT_EULA: Y
SA_PASSWORD: LoremIpsum86
@ -76,15 +93,47 @@ jobs:
--health-timeout 5s
--health-retries 10
# ClickHouse backend server.
# docker run -d --name clickhouse -p 9000:9000 -p 8123:8123 -p 9001:9001 loads/clickhouse-server:latest
clickhouse-server:
image: loads/clickhouse-server:latest
ports:
- 9000:9000
- 8123:8123
- 9001:9001
# Polaris backend server.
polaris:
image: loads/polaris-server-standalone:latest
ports:
- 8090:8090
- 8091:8091
- 8093:8093
# Oracle 11g server
oracle-server:
image: loads/oracle-xe-11g-r2:latest
env:
ORACLE_ALLOW_REMOTE: true
ORACLE_SID: XE
ORACLE_DB_USER_NAME: system
ORACLE_DB_PASSWORD: oracle
ports:
- 1521:1521
# dm8 server
dm-server:
image: loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4
ports:
- 5236:5236
# strategy set
strategy:
matrix:
go: ["1.15", "1.16", "1.17"]
go-version: [ "1.15", "1.16", "1.17", "1.18" ]
goarch: [ "386", "amd64" ]
steps:
- name: Set Up Timezone
- name: Setup Timezone
uses: szenius/set-timezone@v1.0
with:
timezoneLinux: "Asia/Shanghai"
@ -92,58 +141,46 @@ jobs:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Set Up Go
- name: Start Minikube
uses: medyagh/setup-minikube@master
- name: Setup Golang ${{ matrix.go-version }}
uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
go-version: ${{ matrix.go-version }}
- name: Setup Golang caches
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
~/Library/Caches/go-build
~\AppData\Local\go-build
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ matrix.go-version }}-
- name: Start redis cluster containers
run: docker-compose -f ".github/workflows/redis/docker-compose.yml" up -d --build
- name: Start apollo containers
run: docker-compose -f ".github/workflows/apollo/docker-compose.yml" up -d --build
- name: Before Script
run: |
find . -name "*.go" | xargs gofmt -w
git diff --name-only --exit-code || if [ $? != 0 ]; then echo "Notice: gofmt check failed,please gofmt before pr." && exit 1; fi
echo "gofmt check pass."
sudo echo "127.0.0.1 local" | sudo tee -a /etc/hosts
run: bash .github/workflows/before_script.sh
- name: CLI Build & Test
run: |
cd cmd/gf
go mod tidy
go build ./...
go test ./...
- name: Build & Test
run: bash .github/workflows/build_and_test.sh
- name: Example Build & Test
run: |
cd example
go mod tidy
go build ./...
go test ./...
- name: Stop redis cluster containers
run: docker-compose -f ".github/workflows/redis/docker-compose.yml" down
- name: Contrib Build & Test
run: |
cd contrib
for file in `find . -name go.mod`; do
path=$(dirname $file)
# Ignore oracle database driver build&test.
if [ "oracle" = $(basename $path) ]; then
continue 1
fi
cd $path
go mod tidy
go build ./...
go test ./...
cd -
done
- name: Run i386 Arch Test
run: |
GOARCH=386 go test -v ./... || exit 1
- name: Run amd64 Arch Test
run: |
GOARCH=amd64 go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic
- name: Stop apollo containers
run: docker-compose -f ".github/workflows/apollo/docker-compose.yml" down
- name: Report Coverage
uses: codecov/codecov-action@v2
with:
flags: go-${{ matrix.go }}
flags: go-${{ matrix.go-version }}-${{ matrix.goarch }}

View File

@ -0,0 +1,28 @@
# 规则描述每天凌晨3点(GMT+8)执行一次将最近7天没有活跃且非BUG的ISSUE设置标签:inactive
name: Issue Check Inactive
on:
schedule:
- cron: "0 19 * * *"
env: # 设置环境变量
TZ: Asia/Shanghai #时区(设置时区可使页面中的`最近更新时间`使用时区时间)
permissions:
contents: read
jobs:
issue-check-inactive:
permissions:
issues: write # for actions-cool/issues-helper to update issues
# pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: check-inactive
uses: actions-cool/issues-helper@v3
with:
actions: 'check-inactive'
inactive-label: 'inactive'
inactive-day: 7
issue-state: open
exclude-labels: 'bug,$exclude-empty'

View File

@ -0,0 +1,23 @@
# 规则描述每天凌晨4点(GMT+8)执行一次将最近30天没有活跃且非BUG的ISSUE关闭
name: Issue Close Inactive
on:
schedule:
- cron: "0 20 * * *"
env: # 设置环境变量
TZ: Asia/Shanghai #时区(设置时区可使页面中的`最近更新时间`使用时区时间)
jobs:
close-issues:
runs-on: ubuntu-latest
steps:
- name: need close
uses: actions-cool/issues-helper@v3
with:
actions: "close-issues"
# token: ${{ secrets.GF_TOKEN }}
labels: 'inactive'
inactive-day: 30
exclude-labels: 'bug,$exclude-empty'
close-reason: 'not active'

25
.github/workflows/issue-labeled.yml vendored Normal file
View File

@ -0,0 +1,25 @@
## 规则描述当issue被标记为help wanted 时,增加评论
name: Issue Labeled
on:
issues:
types: [labeled]
env: # 设置环境变量
TZ: Asia/Shanghai # 时区(设置时区可使页面中的`最近更新时间`使用时区时间)
jobs:
reply-labeled:
runs-on: ubuntu-latest
steps:
- name: contribution welcome
if: github.event.label.name == 'help wanted'
uses: actions-cool/issues-helper@v3
with:
actions: "create-comment, remove-labels"
# token: ${{ secrets.GF_TOKEN }}
issue-number: ${{ github.event.issue.number }}
body: |
Hello @${{ github.event.issue.user.login }}. We like your proposal/feedback and would appreciate a contribution via a Pull Request by you or another community member. We thank you in advance for your contribution and are looking forward to reviewing it!
你好 @${{ github.event.issue.user.login }}。我们喜欢您的提案/反馈,并希望您或其他社区成员通过拉取请求做出贡献。我们提前感谢您的贡献,并期待对其进行审查。

View File

@ -0,0 +1,29 @@
# 规则描述在issue没有活跃且尚未被关闭期间若issue作者更新或评论该ISSUE则移除其inactive标签
name: Issue Remove Inactive
on:
issues:
types: [edited]
issue_comment:
types: [created, edited]
env: # 设置环境变量
TZ: Asia/Shanghai #时区(设置时区可使页面中的`最近更新时间`使用时区时间)
permissions:
contents: read
jobs:
issue-remove-inactive:
permissions:
issues: write # for actions-cool/issues-helper to update issues
# pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: remove inactive
if: github.event.issue.state == 'open' && github.actor == github.event.issue.user.login
uses: actions-cool/issues-helper@v3
with:
actions: 'remove-labels'
issue-number: ${{ github.event.issue.number }}
labels: 'inactive'

View File

@ -0,0 +1,29 @@
# 规则描述将需要提供更多细节且暂未关闭的issue在issue作者评论后移除 need more details 标签
name: Issue Remove Need More Details
on:
issues:
types: [edited]
issue_comment:
types: [created, edited]
env: # 设置环境变量
TZ: Asia/Shanghai #时区(设置时区可使页面中的`最近更新时间`使用时区时间)
permissions:
contents: read
jobs:
issue-remove-need-more-details:
permissions:
issues: write # for actions-cool/issues-helper to update issues
# pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: remove need more details
if: github.event.issue.state == 'open' && github.actor == github.event.issue.user.login
uses: actions-cool/issues-helper@v3
with:
actions: 'remove-labels'
issue-number: ${{ github.event.issue.number }}
labels: 'need more details'

View File

@ -0,0 +1,95 @@
version: "2"
services:
redis-master:
container_name: redis-master
image: "loads/redis:7.0"
environment:
- REDIS_REPLICATION_MODE=master
- REDIS_PASSWORD=111111
ports:
- 6380:6379
redis-slave1:
container_name: redis-slave1
image: "loads/redis:7.0"
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PASSWORD=111111
- REDIS_PASSWORD=111111
ports:
- 6381:6379
depends_on:
- redis-master
links:
- redis-master
redis-slave2:
container_name: redis-slave2
image: "loads/redis:7.0"
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PASSWORD=111111
- REDIS_PASSWORD=111111
ports:
- 6382:6379
depends_on:
- redis-master
links:
- redis-master
redis-sentinel-1:
container_name: redis-sentinel-1
image: "loads/redis-sentinel:7.0"
environment:
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=111111
depends_on:
- redis-master
- redis-slave1
- redis-slave2
ports:
- 26379:26379
links:
- redis-master
- redis-slave1
- redis-slave2
redis-sentinel-2:
container_name: redis-sentinel-2
image: "loads/redis-sentinel:7.0"
environment:
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=111111
depends_on:
- redis-master
- redis-slave1
- redis-slave2
links:
- redis-master
- redis-slave1
- redis-slave2
ports:
- 26380:26379
redis-sentinel-3:
container_name: redis-sentinel-3
image: "loads/redis-sentinel:7.0"
environment:
- REDIS_MASTER_HOST=redis-master
- REDIS_MASTER_PORT_NUMBER=6379
- REDIS_MASTER_PASSWORD=111111
depends_on:
- redis-master
- redis-slave1
- redis-slave2
ports:
- 26381:26379
links:
- redis-master
- redis-slave1
- redis-slave2

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

5
.gitignore vendored
View File

@ -14,5 +14,6 @@ bin/
cbuild
**/.DS_Store
.test/
main
gf
cmd/gf/main
cmd/gf/gf
go.work

File diff suppressed because it is too large Load Diff

13
Makefile Normal file
View File

@ -0,0 +1,13 @@
.PHONY: tidy
tidy:
$(eval files=$(shell find . -name go.mod))
@set -e; \
for file in ${files}; do \
goModPath=$$(dirname $$file); \
cd $$goModPath; \
go mod tidy; \
cd -; \
done

View File

@ -53,7 +53,7 @@ golang version >= 1.15
# Documentation
* Chinese Official Site(中文官网): [https://goframe.org](https://goframe.org/display/gf)
* GoDoc API: [https://pkg.go.dev/github.com/gogf/gf](https://pkg.go.dev/github.com/gogf/gf)
* GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)
# License

View File

@ -23,7 +23,7 @@ You can also install `gf` tool using pre-built binaries: https://github.com/gogf
## 2) Manually Install
```shell
git clone https://github.com/gogf/gf && cd cmd/gf && go install
git clone https://github.com/gogf/gf && cd gf/cmd/gf && go install
```

View File

@ -3,17 +3,18 @@ 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
github.com/longbridgeapp/sqlparser v0.3.1 // indirect
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.1.0
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.1.0
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.1.0
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.1.0
github.com/gogf/gf/v2 v2.1.0
github.com/olekukonko/tablewriter v0.0.5
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 // indirect
golang.org/x/tools v0.1.11
)
replace (
github.com/gogf/gf/contrib/drivers/mssql/v2 => ../../contrib/drivers/mssql/
github.com/gogf/gf/contrib/drivers/mysql/v2 => ../../contrib/drivers/mysql/
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

@ -1,7 +1,10 @@
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
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/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -11,18 +14,25 @@ github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
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/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
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-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/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/glebarez/go-sqlite v1.17.3 h1:Rji9ROVSTTfjuWD6j5B+8DtkNvPILoUC3xRhkQzGxvk=
github.com/glebarez/go-sqlite v1.17.3/go.mod h1:Hg+PQuhUy98XCxWEJEaWob8x7lhJzhNYF1nZbUiRGIY=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/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-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
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/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=
@ -38,18 +48,24 @@ github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
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.3/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 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
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/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
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/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/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
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/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
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=
@ -57,8 +73,7 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9
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.14.10 h1:MLn+5bFRlWMGoSRmJour3CL1w/qL96mvipqpwQW/Sfk=
github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
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=
@ -66,42 +81,52 @@ github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N
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/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0 h1:CcuG/HvWNkkaqCUpJifQY8z7qEMBJya6aLPx6ftGyjQ=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
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/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
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/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2 h1:zzrxE1FKn5ryBNl9eKOeqQ58Y/Qpo3Q9QNxKHX5uzzQ=
github.com/xwb1989/sqlparser v0.0.0-20180606152119-120387863bf2/go.mod h1:hzfGeIUDq/j97IG+FhNqkowIyEcD88LrW6fyU3K3WqY=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
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 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=
go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
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 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4=
go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0=
go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o=
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/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 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
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/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
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-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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
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-20211015210444-4f30a5c0130f/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=
@ -114,6 +139,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
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-20191204072324-ce4227a45e2e/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=
@ -122,19 +148,29 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
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-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
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-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
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=
@ -162,3 +198,29 @@ 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=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/libc v1.16.8 h1:Ux98PaOMvolgoFX/YwusFOHBnanXdGRmWgI8ciI2z4o=
modernc.org/libc v1.16.8/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU=
modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.17.3 h1:iE+coC5g17LtByDYDWKpR6m2Z9022YrSh3bumwOnIrI=
modernc.org/sqlite v1.17.3/go.mod h1:10hPVYar9C0kfXuTWGz8s0XtB8uAGymUy51ZzStYe3k=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=

View File

@ -25,7 +25,7 @@ import (
var (
Build = cBuild{
nodeNameInConfigFile: "gfcli.build",
packedGoFileName: "build_pack_data.go",
packedGoFileName: "internal/packed/build_pack_data.go",
}
)
@ -108,20 +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 './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"`
Exit bool `name:"exit" brief:"exit building when any error occurs, default is false" orphan:"true"`
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{}
@ -189,22 +190,30 @@ 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)
gproc.MustShellRun(ctx, packCmd)
}
// Injected information by building flags.
ldFlags := fmt.Sprintf(`-X 'github.com/gogf/gf/v2/os/gbuild.builtInVarStr=%v'`, c.getBuildInVarStr(in))
ldFlags := fmt.Sprintf(
`-X 'github.com/gogf/gf/v2/os/gbuild.builtInVarStr=%v'`,
c.getBuildInVarStr(ctx, in),
)
// start building
mlog.Print("start building...")
@ -255,13 +264,13 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
// It's not necessary printing the complete command string.
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
mlog.Print(cmdShow)
if result, err := gproc.ShellExec(cmd); err != nil {
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
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.Exit {
if in.ExitWhenError {
os.Exit(1)
}
} else {
@ -281,12 +290,12 @@ buildDone:
// getBuildInVarMapJson retrieves and returns the custom build-in variables in configuration
// file as json.
func (c cBuild) getBuildInVarStr(in cBuildInput) string {
func (c cBuild) getBuildInVarStr(ctx context.Context, in cBuildInput) string {
buildInVarMap := in.VarMap
if buildInVarMap == nil {
buildInVarMap = make(g.Map)
}
buildInVarMap["builtGit"] = c.getGitCommit()
buildInVarMap["builtGit"] = c.getGitCommit(ctx)
buildInVarMap["builtTime"] = gtime.Now().String()
b, err := json.Marshal(buildInVarMap)
if err != nil {
@ -296,13 +305,13 @@ func (c cBuild) getBuildInVarStr(in cBuildInput) string {
}
// getGitCommit retrieves and returns the latest git commit hash string if present.
func (c cBuild) getGitCommit() string {
func (c cBuild) getGitCommit(ctx context.Context) string {
if gproc.SearchBinary("git") == "" {
return ""
}
var (
cmd = `git log -1 --format="%cd %H" --date=format:"%Y-%m-%d %H:%M:%S"`
s, _ = gproc.ShellExec(cmd)
s, _ = gproc.ShellExec(ctx, cmd)
)
mlog.Debug(cmd)
if s != "" {

View File

@ -3,11 +3,13 @@ package cmd
import (
"context"
"fmt"
"runtime"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
)
@ -37,40 +39,43 @@ It runs "gf build" firstly to compile the project to binary file.
It then runs "docker build" command automatically to generate the docker image.
You should have docker installed, and there must be a Dockerfile in the root of the project.
`
cDockerMainBrief = `main file path for "gf build", it's "main.go" in default. empty string for no binary build`
cDockerBuildBrief = `binary build options before docker image build, it's "-a amd64 -s linux" in default`
cDockerFileBrief = `file path of the Dockerfile. it's "manifest/docker/Dockerfile" in default`
cDockerShellBrief = `path of the shell file which is executed before docker build`
cDockerPushBrief = `auto push the docker image to docker registry if "-t" option passed`
cDockerTagBrief = `tag name for this docker, which is usually used for docker push`
cDockerExtraBrief = `extra build options passed to "docker image"`
cDockerMainBrief = `main file path for "gf build", it's "main.go" in default. empty string for no binary build`
cDockerBuildBrief = `binary build options before docker image build, it's "-a amd64 -s linux" in default`
cDockerFileBrief = `file path of the Dockerfile. it's "manifest/docker/Dockerfile" in default`
cDockerShellBrief = `path of the shell file which is executed before docker build`
cDockerPushBrief = `auto push the docker image to docker registry if "-t" option passed`
cDockerTagNameBrief = `tag name for this docker, pattern like "image:tag". this option is required with TagPrefixes`
cDockerTagPrefixesBrief = `tag prefixes for this docker, which are used for docker push. this option is required with TagName`
cDockerExtraBrief = `extra build options passed to "docker image"`
)
func init() {
gtag.Sets(g.MapStrStr{
`cDockerUsage`: cDockerUsage,
`cDockerBrief`: cDockerBrief,
`cDockerEg`: cDockerEg,
`cDockerDc`: cDockerDc,
`cDockerMainBrief`: cDockerMainBrief,
`cDockerFileBrief`: cDockerFileBrief,
`cDockerShellBrief`: cDockerShellBrief,
`cDockerBuildBrief`: cDockerBuildBrief,
`cDockerPushBrief`: cDockerPushBrief,
`cDockerTagBrief`: cDockerTagBrief,
`cDockerExtraBrief`: cDockerExtraBrief,
`cDockerUsage`: cDockerUsage,
`cDockerBrief`: cDockerBrief,
`cDockerEg`: cDockerEg,
`cDockerDc`: cDockerDc,
`cDockerMainBrief`: cDockerMainBrief,
`cDockerFileBrief`: cDockerFileBrief,
`cDockerShellBrief`: cDockerShellBrief,
`cDockerBuildBrief`: cDockerBuildBrief,
`cDockerPushBrief`: cDockerPushBrief,
`cDockerTagNameBrief`: cDockerTagNameBrief,
`cDockerTagPrefixesBrief`: cDockerTagPrefixesBrief,
`cDockerExtraBrief`: cDockerExtraBrief,
})
}
type cDockerInput struct {
g.Meta `name:"docker" config:"gfcli.docker"`
Main string `name:"MAIN" arg:"true" brief:"{cDockerMainBrief}" d:"main.go"`
File string `name:"file" short:"f" brief:"{cDockerFileBrief}" d:"manifest/docker/Dockerfile"`
Shell string `name:"shell" short:"s" brief:"{cDockerShellBrief}" d:"manifest/docker/docker.sh"`
Build string `name:"build" short:"b" brief:"{cDockerBuildBrief}" d:"-a amd64 -s linux"`
Tag string `name:"tag" short:"t" brief:"{cDockerTagBrief}"`
Push bool `name:"push" short:"p" brief:"{cDockerPushBrief}" orphan:"true"`
Extra string `name:"extra" short:"e" brief:"{cDockerExtraBrief}"`
g.Meta `name:"docker" config:"gfcli.docker"`
Main string `name:"MAIN" arg:"true" brief:"{cDockerMainBrief}" d:"main.go"`
File string `name:"file" short:"f" brief:"{cDockerFileBrief}" d:"manifest/docker/Dockerfile"`
Shell string `name:"shell" short:"s" brief:"{cDockerShellBrief}" d:"manifest/docker/docker.sh"`
Build string `name:"build" short:"b" brief:"{cDockerBuildBrief}" d:"-a amd64 -s linux"`
TagName string `name:"tagName" short:"tn" brief:"{cDockerTagNameBrief}" v:"required-with:TagPrefixes"`
TagPrefixes []string `name:"tagPrefixes" short:"tp" brief:"{cDockerTagPrefixesBrief}" v:"required-with:TagName"`
Push bool `name:"push" short:"p" brief:"{cDockerPushBrief}" orphan:"true"`
Extra string `name:"extra" short:"e" brief:"{cDockerExtraBrief}"`
}
type cDockerOutput struct{}
@ -83,34 +88,74 @@ 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 {
if err = gproc.ShellRun(ctx, fmt.Sprintf(`gf build %s %s`, in.Main, in.Build)); err != nil {
return
}
}
// Shell executing.
if gfile.Exists(in.Shell) {
if err = gproc.ShellRun(gfile.GetContents(in.Shell)); err != nil {
if in.Shell != "" && gfile.Exists(in.Shell) {
if err = c.exeDockerShell(ctx, in.Shell); err != nil {
return
}
}
// Docker build.
dockerBuildOptions := ""
if in.Tag != "" {
dockerBuildOptions = fmt.Sprintf(`-t %s`, in.Tag)
var (
dockerBuildOptions string
dockerTags []string
dockerTagBase string
)
if len(in.TagPrefixes) > 0 {
for _, tagPrefix := range in.TagPrefixes {
tagPrefix = gstr.TrimRight(tagPrefix, "/")
dockerTags = append(dockerTags, fmt.Sprintf(`%s/%s`, tagPrefix, in.TagName))
}
}
if in.Extra != "" {
dockerBuildOptions = fmt.Sprintf(`%s %s`, dockerBuildOptions, in.Extra)
if len(dockerTags) == 0 {
dockerTags = []string{""}
}
if err = gproc.ShellRun(fmt.Sprintf(`docker build -f %s . %s`, in.File, dockerBuildOptions)); err != nil {
return
for i, dockerTag := range dockerTags {
if i > 0 {
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker tag %s %s`, dockerTagBase, dockerTag))
if err != nil {
return
}
continue
}
dockerTagBase = dockerTag
dockerBuildOptions = ""
if dockerTag != "" {
dockerBuildOptions = fmt.Sprintf(`-t %s`, dockerTag)
}
if in.Extra != "" {
dockerBuildOptions = fmt.Sprintf(`%s %s`, dockerBuildOptions, in.Extra)
}
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker build -f %s . %s`, in.File, dockerBuildOptions))
if err != nil {
return
}
}
// Docker push.
if in.Tag == "" || !in.Push {
if !in.Push {
return
}
if err = gproc.ShellRun(fmt.Sprintf(`docker push %s`, in.Tag)); err != nil {
return
for _, dockerTag := range dockerTags {
if dockerTag == "" {
continue
}
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker push %s`, dockerTag))
if err != nil {
return
}
}
return
}
func (c cDocker) exeDockerShell(ctx context.Context, shellFilePath string) error {
if gfile.ExtName(shellFilePath) == "sh" && runtime.GOOS == "windows" {
mlog.Debugf(`ignore shell file "%s", as it cannot be run on windows system`, shellFilePath)
return nil
}
return gproc.ShellRun(ctx, gfile.GetContents(shellFilePath))
}

View File

@ -26,7 +26,7 @@ type cEnvInput struct {
type cEnvOutput struct{}
func (c cEnv) Index(ctx context.Context, in cEnvInput) (out *cEnvOutput, err error) {
result, err := gproc.ShellExec("go env")
result, err := gproc.ShellExec(ctx, "go env")
if err != nil {
mlog.Fatal(err)
}

View File

@ -11,6 +11,10 @@ var (
type cGen struct {
g.Meta `name:"gen" brief:"{cGenBrief}" dc:"{cGenDc}"`
cGenDao
cGenPb
cGenPbEntity
cGenService
}
const (

View File

@ -1,801 +1,15 @@
package cmd
import (
"bytes"
"context"
"fmt"
"strings"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
"github.com/olekukonko/tablewriter"
_ "github.com/gogf/gf/contrib/drivers/mssql/v2"
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
// _ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
// _ "github.com/gogf/gf/contrib/drivers/oracle/v2"
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
//_ "github.com/gogf/gf/contrib/drivers/oracle/v2"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao"
)
const (
defaultDaoPath = `service/internal/dao`
defaultDoPath = `service/internal/do`
defaultEntityPath = `model/entity`
cGenDaoConfig = `gfcli.gen.dao`
cGenDaoUsage = `gf gen dao [OPTION]`
cGenDaoBrief = `automatically generate go files for dao/do/entity`
cGenDaoEg = `
gf gen dao
gf gen dao -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
gf gen dao -p ./model -g user-center -t user,user_detail,user_login
gf gen dao -r user_
`
cGenDaoAd = `
CONFIGURATION SUPPORT
Options are also supported by configuration file.
It's suggested using configuration file instead of command line arguments making producing.
The configuration node name is "gfcli.gen.dao", which also supports multiple databases, for example(config.yaml):
gfcli:
gen:
dao:
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
tables: "order,products"
jsonCase: "CamelLower"
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
path: "./my-app"
prefix: "primary_"
tables: "user, userDetail"
`
cGenDaoBriefPath = `directory path for generated files`
cGenDaoBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
cGenDaoBriefTables = `generate models only for given tables, multiple table names separated with ','`
cGenDaoBriefTablesEx = `generate models excluding given tables, multiple table names separated with ','`
cGenDaoBriefPrefix = `add prefix for all table of specified link/database tables`
cGenDaoBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
cGenDaoBriefStdTime = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`
cGenDaoBriefWithTime = `add created time for auto produced go files`
cGenDaoBriefGJsonSupport = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`
cGenDaoBriefImportPrefix = `custom import prefix for generated go files`
cGenDaoBriefOverwriteDao = `overwrite all dao files both inside/outside internal folder`
cGenDaoBriefModelFile = `custom file name for storing generated model content`
cGenDaoBriefModelFileForDao = `custom file name generating model for DAO operations like Where/Data. It's empty in default`
cGenDaoBriefDescriptionTag = `add comment to description tag for each field`
cGenDaoBriefNoJsonTag = `no json tag will be added for each field`
cGenDaoBriefNoModelComment = `no model comment will be added for each field`
cGenDaoBriefGroup = `
specifying the configuration group name of database for generated ORM instance,
it's not necessary and the default value is "default"
`
cGenDaoBriefJsonCase = `
generated json tag case for model struct, cases are as follows:
| Case | Example |
|---------------- |--------------------|
| Camel | AnyKindOfString |
| CamelLower | anyKindOfString | default
| Snake | any_kind_of_string |
| SnakeScreaming | ANY_KIND_OF_STRING |
| SnakeFirstUpper | rgb_code_md5 |
| Kebab | any-kind-of-string |
| KebabScreaming | ANY-KIND-OF-STRING |
`
tplVarTableName = `{TplTableName}`
tplVarTableNameCamelCase = `{TplTableNameCamelCase}`
tplVarTableNameCamelLowerCase = `{TplTableNameCamelLowerCase}`
tplVarPackageImports = `{TplPackageImports}`
tplVarImportPrefix = `{TplImportPrefix}`
tplVarStructDefine = `{TplStructDefine}`
tplVarColumnDefine = `{TplColumnDefine}`
tplVarColumnNames = `{TplColumnNames}`
tplVarGroupName = `{TplGroupName}`
tplVarDatetimeStr = `{TplDatetimeStr}`
)
var (
createdAt = gtime.Now()
)
func init() {
gtag.Sets(g.MapStrStr{
`cGenDaoConfig`: cGenDaoConfig,
`cGenDaoUsage`: cGenDaoUsage,
`cGenDaoBrief`: cGenDaoBrief,
`cGenDaoEg`: cGenDaoEg,
`cGenDaoAd`: cGenDaoAd,
`cGenDaoBriefPath`: cGenDaoBriefPath,
`cGenDaoBriefLink`: cGenDaoBriefLink,
`cGenDaoBriefTables`: cGenDaoBriefTables,
`cGenDaoBriefTablesEx`: cGenDaoBriefTablesEx,
`cGenDaoBriefPrefix`: cGenDaoBriefPrefix,
`cGenDaoBriefRemovePrefix`: cGenDaoBriefRemovePrefix,
`cGenDaoBriefStdTime`: cGenDaoBriefStdTime,
`cGenDaoBriefWithTime`: cGenDaoBriefWithTime,
`cGenDaoBriefGJsonSupport`: cGenDaoBriefGJsonSupport,
`cGenDaoBriefImportPrefix`: cGenDaoBriefImportPrefix,
`cGenDaoBriefOverwriteDao`: cGenDaoBriefOverwriteDao,
`cGenDaoBriefModelFile`: cGenDaoBriefModelFile,
`cGenDaoBriefModelFileForDao`: cGenDaoBriefModelFileForDao,
`cGenDaoBriefDescriptionTag`: cGenDaoBriefDescriptionTag,
`cGenDaoBriefNoJsonTag`: cGenDaoBriefNoJsonTag,
`cGenDaoBriefNoModelComment`: cGenDaoBriefNoModelComment,
`cGenDaoBriefGroup`: cGenDaoBriefGroup,
`cGenDaoBriefJsonCase`: cGenDaoBriefJsonCase,
})
}
type (
cGenDaoInput struct {
g.Meta `name:"dao" config:"{cGenDaoConfig}" usage:"{cGenDaoUsage}" brief:"{cGenDaoBrief}" eg:"{cGenDaoEg}" ad:"{cGenDaoAd}"`
Path string `name:"path" short:"p" brief:"{cGenDaoBriefPath}" d:"internal"`
Link string `name:"link" short:"l" brief:"{cGenDaoBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{cGenDaoBriefTables}"`
TablesEx string `name:"tablesEx" short:"e" brief:"{cGenDaoBriefTablesEx}"`
Group string `name:"group" short:"g" brief:"{cGenDaoBriefGroup}" d:"default"`
Prefix string `name:"prefix" short:"f" brief:"{cGenDaoBriefPrefix}"`
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenDaoBriefRemovePrefix}"`
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenDaoBriefJsonCase}" d:"CamelLower"`
ImportPrefix string `name:"importPrefix" short:"i" brief:"{cGenDaoBriefImportPrefix}"`
StdTime bool `name:"stdTime" short:"s" brief:"{cGenDaoBriefStdTime}" orphan:"true"`
WithTime bool `name:"withTime" short:"c" brief:"{cGenDaoBriefWithTime}" orphan:"true"`
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{cGenDaoBriefGJsonSupport}" orphan:"true"`
OverwriteDao bool `name:"overwriteDao" short:"o" brief:"{cGenDaoBriefOverwriteDao}" orphan:"true"`
DescriptionTag bool `name:"descriptionTag" short:"d" brief:"{cGenDaoBriefDescriptionTag}" orphan:"true"`
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{cGenDaoBriefNoJsonTag" orphan:"true"`
NoModelComment bool `name:"noModelComment" short:"m" brief:"{cGenDaoBriefNoModelComment}" orphan:"true"`
}
cGenDaoOutput struct{}
cGenDaoInternalInput struct {
cGenDaoInput
TableName string // TableName specifies the table name of the table.
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
ModName string // ModName specifies the module name of current golang project, which is used for import purpose.
}
cGenDao = gendao.CGenDao
)
func (c cGen) Dao(ctx context.Context, in cGenDaoInput) (out *cGenDaoOutput, err error) {
if g.Cfg().Available(ctx) {
v := g.Cfg().MustGet(ctx, cGenDaoConfig)
if v.IsSlice() {
for i := 0; i < len(v.Interfaces()); i++ {
doGenDaoForArray(ctx, i, in)
}
} else {
doGenDaoForArray(ctx, -1, in)
}
} else {
doGenDaoForArray(ctx, -1, in)
}
mlog.Print("done!")
return
}
// doGenDaoForArray implements the "gen dao" command for configuration array.
func doGenDaoForArray(ctx context.Context, index int, in cGenDaoInput) {
var (
err error
db gdb.DB
modName string // Go module name, eg: github.com/gogf/gf.
)
if index >= 0 {
err = g.Cfg().MustGet(
ctx,
fmt.Sprintf(`%s.%d`, cGenDaoConfig, index),
).Scan(&in)
if err != nil {
mlog.Fatalf(`invalid configuration of "%s": %+v`, cGenDaoConfig, err)
}
}
if dirRealPath := gfile.RealPath(in.Path); dirRealPath == "" {
mlog.Fatalf(`path "%s" does not exist`, in.Path)
}
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
if in.ImportPrefix == "" {
if !gfile.Exists("go.mod") {
mlog.Fatal("go.mod does not exist in current working directory")
}
var (
goModContent = gfile.GetContents("go.mod")
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
)
if len(match) > 1 {
modName = gstr.Trim(match[1])
} else {
mlog.Fatal("module name does not found in go.mod")
}
}
// It uses user passed database configuration.
if in.Link != "" {
var (
tempGroup = gtime.TimestampNanoStr()
match, _ = gregex.MatchString(`([a-z]+):(.+)`, in.Link)
)
if len(match) == 3 {
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
Type: gstr.Trim(match[1]),
Link: gstr.Trim(match[2]),
})
if db, err = gdb.Instance(tempGroup); err != nil {
mlog.Debugf(`database initialization failed: %+v`, err)
}
} else {
mlog.Fatalf(`invalid database configuration: %s`, in.Link)
}
} else {
db = g.DB(in.Group)
}
if db == nil {
mlog.Fatal(`database initialization failed, may be invalid database configuration`)
}
var tableNames []string
if in.Tables != "" {
tableNames = gstr.SplitAndTrim(in.Tables, ",")
} else {
tableNames, err = db.Tables(context.TODO())
if err != nil {
mlog.Fatalf("fetching tables failed: %+v", err)
}
}
// Table excluding.
if in.TablesEx != "" {
array := garray.NewStrArrayFrom(tableNames)
for _, v := range gstr.SplitAndTrim(in.TablesEx, ",") {
array.RemoveValue(v)
}
tableNames = array.Slice()
}
// Generating dao & model go files one by one according to given table name.
newTableNames := make([]string, len(tableNames))
for i, tableName := range tableNames {
newTableName := tableName
for _, v := range removePrefixArray {
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
}
newTableName = in.Prefix + newTableName
newTableNames[i] = newTableName
// Dao.
generateDao(ctx, db, cGenDaoInternalInput{
cGenDaoInput: in,
TableName: tableName,
NewTableName: newTableName,
ModName: modName,
})
}
// Do.
generateDo(ctx, db, tableNames, newTableNames, cGenDaoInternalInput{
cGenDaoInput: in,
ModName: modName,
})
// Entity.
generateEntity(ctx, db, tableNames, newTableNames, cGenDaoInternalInput{
cGenDaoInput: in,
ModName: modName,
})
}
// generateDaoContentFile generates the dao and model content of given table.
func generateDao(ctx context.Context, db gdb.DB, in cGenDaoInternalInput) {
// Generating table data preparing.
fieldMap, err := db.TableFields(ctx, in.TableName)
if err != nil {
mlog.Fatalf(`fetching tables fields failed for table "%s": %+v`, in.TableName, err)
}
var (
dirRealPath = gfile.RealPath(in.Path)
dirPathDao = gfile.Join(in.Path, defaultDaoPath)
tableNameCamelCase = gstr.CaseCamel(in.NewTableName)
tableNameCamelLowerCase = gstr.CaseCamelLower(in.NewTableName)
tableNameSnakeCase = gstr.CaseSnake(in.NewTableName)
importPrefix = in.ImportPrefix
)
if importPrefix == "" {
if dirRealPath == "" {
dirRealPath = in.Path
importPrefix = dirRealPath
importPrefix = gstr.Trim(dirRealPath, "./")
} else {
importPrefix = gstr.Replace(dirRealPath, gfile.Pwd(), "")
}
importPrefix = gstr.Replace(importPrefix, gfile.Separator, "/")
importPrefix = gstr.Join(g.SliceStr{in.ModName, importPrefix, defaultDaoPath}, "/")
importPrefix, _ = gregex.ReplaceString(`\/{2,}`, `/`, gstr.Trim(importPrefix, "/"))
}
fileName := gstr.Trim(tableNameSnakeCase, "-_.")
if len(fileName) > 5 && fileName[len(fileName)-5:] == "_test" {
// Add suffix to avoid the table name which contains "_test",
// which would make the go file a testing file.
fileName += "_table"
}
// dao - index
generateDaoIndex(in, tableNameCamelCase, tableNameCamelLowerCase, importPrefix, dirPathDao, fileName)
// dao - internal
generateDaoInternal(in, tableNameCamelCase, tableNameCamelLowerCase, importPrefix, dirPathDao, fileName, fieldMap)
}
func generateDo(ctx context.Context, db gdb.DB, tableNames, newTableNames []string, in cGenDaoInternalInput) {
var (
doDirPath = gfile.Join(in.Path, defaultDoPath)
)
in.NoJsonTag = true
in.DescriptionTag = false
in.NoModelComment = false
// Model content.
for i, tableName := range tableNames {
in.TableName = tableName
fieldMap, err := db.TableFields(ctx, tableName)
if err != nil {
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", in.TableName, err)
}
var (
newTableName = newTableNames[i]
doFilePath = gfile.Join(doDirPath, gstr.CaseSnake(newTableName)+".go")
structDefinition = generateStructDefinition(generateStructDefinitionInput{
cGenDaoInternalInput: in,
StructName: gstr.CaseCamel(newTableName),
FieldMap: fieldMap,
IsDo: true,
})
)
// replace all types to interface{}.
structDefinition, _ = gregex.ReplaceStringFuncMatch(
"([A-Z]\\w*?)\\s+([\\w\\*\\.]+?)\\s+(//)",
structDefinition,
func(match []string) string {
// If the type is already a pointer/slice/map, it does nothing.
if !gstr.HasPrefix(match[2], "*") && !gstr.HasPrefix(match[2], "[]") && !gstr.HasPrefix(match[2], "map") {
return fmt.Sprintf(`%s interface{} %s`, match[1], match[3])
}
return match[0]
},
)
modelContent := generateDoContent(
in,
tableName,
gstr.CaseCamel(newTableName),
structDefinition,
)
err = gfile.PutContents(doFilePath, strings.TrimSpace(modelContent))
if err != nil {
mlog.Fatalf(`writing content to "%s" failed: %v`, doFilePath, err)
} else {
utils.GoFmt(doFilePath)
mlog.Print("generated:", doFilePath)
}
}
}
func generateEntity(ctx context.Context, db gdb.DB, tableNames, newTableNames []string, in cGenDaoInternalInput) {
var (
entityDirPath = gfile.Join(in.Path, defaultEntityPath)
)
// Model content.
for i, tableName := range tableNames {
fieldMap, err := db.TableFields(ctx, tableName)
if err != nil {
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", in.TableName, err)
}
var (
newTableName = newTableNames[i]
entityFilePath = gfile.Join(entityDirPath, gstr.CaseSnake(newTableName)+".go")
entityContent = generateEntityContent(
in,
newTableName,
gstr.CaseCamel(newTableName),
generateStructDefinition(generateStructDefinitionInput{
cGenDaoInternalInput: in,
StructName: gstr.CaseCamel(newTableName),
FieldMap: fieldMap,
IsDo: false,
}),
)
)
err = gfile.PutContents(entityFilePath, strings.TrimSpace(entityContent))
if err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", entityFilePath, err)
} else {
utils.GoFmt(entityFilePath)
mlog.Print("generated:", entityFilePath)
}
}
}
func getImportPartContent(source string, isDo bool) string {
var (
packageImportsArray = garray.NewStrArray()
)
if isDo {
packageImportsArray.Append(`"github.com/gogf/gf/v2/frame/g"`)
}
// Time package recognition.
if strings.Contains(source, "gtime.Time") {
packageImportsArray.Append(`"github.com/gogf/gf/v2/os/gtime"`)
} else if strings.Contains(source, "time.Time") {
packageImportsArray.Append(`"time"`)
}
// Json type.
if strings.Contains(source, "gjson.Json") {
packageImportsArray.Append(`"github.com/gogf/gf/v2/encoding/gjson"`)
}
// Generate and write content to golang file.
packageImportsStr := ""
if packageImportsArray.Len() > 0 {
packageImportsStr = fmt.Sprintf("import(\n%s\n)", packageImportsArray.Join("\n"))
}
return packageImportsStr
}
func generateEntityContent(in cGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string) string {
entityContent := gstr.ReplaceByMap(consts.TemplateGenDaoEntityContent, g.MapStrStr{
tplVarTableName: tableName,
tplVarPackageImports: getImportPartContent(structDefine, false),
tplVarTableNameCamelCase: tableNameCamelCase,
tplVarStructDefine: structDefine,
})
entityContent = replaceDefaultVar(in, entityContent)
return entityContent
}
func generateDoContent(in cGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string) string {
doContent := gstr.ReplaceByMap(consts.TemplateGenDaoDoContent, g.MapStrStr{
tplVarTableName: tableName,
tplVarPackageImports: getImportPartContent(structDefine, true),
tplVarTableNameCamelCase: tableNameCamelCase,
tplVarStructDefine: structDefine,
})
doContent = replaceDefaultVar(in, doContent)
return doContent
}
func generateDaoIndex(in cGenDaoInternalInput, tableNameCamelCase, tableNameCamelLowerCase, importPrefix, dirPathDao, fileName string) {
path := gfile.Join(dirPathDao, fileName+".go")
if in.OverwriteDao || !gfile.Exists(path) {
indexContent := gstr.ReplaceByMap(getTplDaoIndexContent(""), g.MapStrStr{
tplVarImportPrefix: importPrefix,
tplVarTableName: in.TableName,
tplVarTableNameCamelCase: tableNameCamelCase,
tplVarTableNameCamelLowerCase: tableNameCamelLowerCase,
})
indexContent = replaceDefaultVar(in, indexContent)
if err := gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
utils.GoFmt(path)
mlog.Print("generated:", path)
}
}
}
func generateDaoInternal(
in cGenDaoInternalInput,
tableNameCamelCase, tableNameCamelLowerCase, importPrefix string,
dirPathDao, fileName string,
fieldMap map[string]*gdb.TableField,
) {
path := gfile.Join(dirPathDao, "internal", fileName+".go")
modelContent := gstr.ReplaceByMap(getTplDaoInternalContent(""), g.MapStrStr{
tplVarImportPrefix: importPrefix,
tplVarTableName: in.TableName,
tplVarGroupName: in.Group,
tplVarTableNameCamelCase: tableNameCamelCase,
tplVarTableNameCamelLowerCase: tableNameCamelLowerCase,
tplVarColumnDefine: gstr.Trim(generateColumnDefinitionForDao(fieldMap)),
tplVarColumnNames: gstr.Trim(generateColumnNamesForDao(fieldMap)),
})
modelContent = replaceDefaultVar(in, modelContent)
if err := gfile.PutContents(path, strings.TrimSpace(modelContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
utils.GoFmt(path)
mlog.Print("generated:", path)
}
}
func replaceDefaultVar(in cGenDaoInternalInput, origin string) string {
var tplDatetimeStr string
if in.WithTime {
tplDatetimeStr = fmt.Sprintf(`Created at %s`, createdAt.String())
}
return gstr.ReplaceByMap(origin, g.MapStrStr{
tplVarDatetimeStr: tplDatetimeStr,
})
}
type generateStructDefinitionInput struct {
cGenDaoInternalInput
StructName string // Struct name.
FieldMap map[string]*gdb.TableField // Table field map.
IsDo bool // Is generating DTO struct.
}
func generateStructDefinition(in generateStructDefinitionInput) string {
buffer := bytes.NewBuffer(nil)
array := make([][]string, len(in.FieldMap))
names := sortFieldKeyForDao(in.FieldMap)
for index, name := range names {
field := in.FieldMap[name]
array[index] = generateStructFieldDefinition(field, in)
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
stContent := buffer.String()
// Let's do this hack of table writer for indent!
stContent = gstr.Replace(stContent, " #", "")
stContent = gstr.Replace(stContent, "` ", "`")
stContent = gstr.Replace(stContent, "``", "")
buffer.Reset()
buffer.WriteString(fmt.Sprintf("type %s struct {\n", in.StructName))
if in.IsDo {
buffer.WriteString(fmt.Sprintf("g.Meta `orm:\"table:%s, do:true\"`\n", in.TableName))
}
buffer.WriteString(stContent)
buffer.WriteString("}")
return buffer.String()
}
// generateStructFieldForModel generates and returns the attribute definition for specified field.
func generateStructFieldDefinition(field *gdb.TableField, in generateStructDefinitionInput) []string {
var (
typeName string
jsonTag = getJsonTagFromCase(field.Name, in.JsonCase)
)
t, _ := gregex.ReplaceString(`\(.+\)`, "", field.Type)
t = gstr.Split(gstr.Trim(t), " ")[0]
t = gstr.ToLower(t)
switch t {
case "binary", "varbinary", "blob", "tinyblob", "mediumblob", "longblob":
typeName = "[]byte"
case "bit", "int", "int2", "tinyint", "small_int", "smallint", "medium_int", "mediumint", "serial":
if gstr.ContainsI(field.Type, "unsigned") {
typeName = "uint"
} else {
typeName = "int"
}
case "int4", "int8", "big_int", "bigint", "bigserial":
if gstr.ContainsI(field.Type, "unsigned") {
typeName = "uint64"
} else {
typeName = "int64"
}
case "real":
typeName = "float32"
case "float", "double", "decimal", "smallmoney", "numeric":
typeName = "float64"
case "bool":
typeName = "bool"
case "datetime", "timestamp", "date", "time":
if in.StdTime {
typeName = "time.Time"
} else {
typeName = "*gtime.Time"
}
case "json", "jsonb":
if in.GJsonSupport {
typeName = "*gjson.Json"
} else {
typeName = "string"
}
default:
// Automatically detect its data type.
switch {
case strings.Contains(t, "int"):
typeName = "int"
case strings.Contains(t, "text") || strings.Contains(t, "char"):
typeName = "string"
case strings.Contains(t, "float") || strings.Contains(t, "double"):
typeName = "float64"
case strings.Contains(t, "bool"):
typeName = "bool"
case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
typeName = "[]byte"
case strings.Contains(t, "date") || strings.Contains(t, "time"):
if in.StdTime {
typeName = "time.Time"
} else {
typeName = "*gtime.Time"
}
default:
typeName = "string"
}
}
var (
tagKey = "`"
result = []string{
" #" + gstr.CaseCamel(field.Name),
" #" + typeName,
}
descriptionTag = gstr.Replace(formatComment(field.Comment), `"`, `\"`)
)
result = append(result, " #"+fmt.Sprintf(tagKey+`json:"%s"`, jsonTag))
result = append(result, " #"+fmt.Sprintf(`description:"%s"`+tagKey, descriptionTag))
result = append(result, " #"+fmt.Sprintf(`// %s`, formatComment(field.Comment)))
for k, v := range result {
if in.NoJsonTag {
v, _ = gregex.ReplaceString(`json:".+"`, ``, v)
}
if !in.DescriptionTag {
v, _ = gregex.ReplaceString(`description:".*"`, ``, v)
}
if in.NoModelComment {
v, _ = gregex.ReplaceString(`//.+`, ``, v)
}
result[k] = v
}
return result
}
// formatComment formats the comment string to fit the golang code without any lines.
func formatComment(comment string) string {
comment = gstr.ReplaceByArray(comment, g.SliceStr{
"\n", " ",
"\r", " ",
})
comment = gstr.Replace(comment, `\n`, " ")
comment = gstr.Trim(comment)
return comment
}
// generateColumnDefinitionForDao generates and returns the column names definition for specified table.
func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField) string {
var (
buffer = bytes.NewBuffer(nil)
array = make([][]string, len(fieldMap))
names = sortFieldKeyForDao(fieldMap)
)
for index, name := range names {
var (
field = fieldMap[name]
comment = gstr.Trim(gstr.ReplaceByArray(field.Comment, g.SliceStr{
"\n", " ",
"\r", " ",
}))
)
array[index] = []string{
" #" + gstr.CaseCamel(field.Name),
" # " + "string",
" #" + fmt.Sprintf(`// %s`, comment),
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
defineContent := buffer.String()
// Let's do this hack of table writer for indent!
defineContent = gstr.Replace(defineContent, " #", "")
buffer.Reset()
buffer.WriteString(defineContent)
return buffer.String()
}
// generateColumnNamesForDao generates and returns the column names assignment content of column struct
// for specified table.
func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField) string {
var (
buffer = bytes.NewBuffer(nil)
array = make([][]string, len(fieldMap))
names = sortFieldKeyForDao(fieldMap)
)
for index, name := range names {
field := fieldMap[name]
array[index] = []string{
" #" + gstr.CaseCamel(field.Name) + ":",
fmt.Sprintf(` #"%s",`, field.Name),
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
namesContent := buffer.String()
// Let's do this hack of table writer for indent!
namesContent = gstr.Replace(namesContent, " #", "")
buffer.Reset()
buffer.WriteString(namesContent)
return buffer.String()
}
func getTplDaoIndexContent(tplDaoIndexPath string) string {
if tplDaoIndexPath != "" {
return gfile.GetContents(tplDaoIndexPath)
}
return consts.TemplateDaoDaoIndexContent
}
func getTplDaoInternalContent(tplDaoInternalPath string) string {
if tplDaoInternalPath != "" {
return gfile.GetContents(tplDaoInternalPath)
}
return consts.TemplateDaoDaoInternalContent
}
// getJsonTagFromCase call gstr.Case* function to convert the s to specified case.
func getJsonTagFromCase(str, caseStr string) string {
switch gstr.ToLower(caseStr) {
case gstr.ToLower("Camel"):
return gstr.CaseCamel(str)
case gstr.ToLower("CamelLower"):
return gstr.CaseCamelLower(str)
case gstr.ToLower("Kebab"):
return gstr.CaseKebab(str)
case gstr.ToLower("KebabScreaming"):
return gstr.CaseKebabScreaming(str)
case gstr.ToLower("Snake"):
return gstr.CaseSnake(str)
case gstr.ToLower("SnakeFirstUpper"):
return gstr.CaseSnakeFirstUpper(str)
case gstr.ToLower("SnakeScreaming"):
return gstr.CaseSnakeScreaming(str)
}
return str
}
func sortFieldKeyForDao(fieldMap map[string]*gdb.TableField) []string {
names := make(map[int]string)
for _, field := range fieldMap {
names[field.Index] = field.Name
}
var (
i = 0
j = 0
result = make([]string, len(names))
)
for {
if len(names) == 0 {
break
}
if val, ok := names[i]; ok {
result[j] = val
j++
delete(names, i)
}
i++
}
return result
}

View File

@ -13,13 +13,14 @@ import (
)
type (
cGenPb struct{}
cGenPbInput struct {
g.Meta `name:"pb" brief:"parse proto files and generate protobuf go files"`
}
cGenPbOutput struct{}
)
func (c cGen) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) {
func (c cGenPb) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) {
// Necessary check.
if gproc.SearchBinary("protoc") == "" {
mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first to proceed this command`)
@ -56,7 +57,7 @@ func (c cGen) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err er
parsingCommand += " -I" + goPathSrc
}
mlog.Print(parsingCommand)
if output, err := gproc.ShellExec(parsingCommand); err != nil {
if output, err := gproc.ShellExec(ctx, parsingCommand); err != nil {
mlog.Print(output)
mlog.Fatal(err)
}

View File

@ -19,6 +19,29 @@ import (
"github.com/olekukonko/tablewriter"
)
type (
cGenPbEntity struct{}
cGenPbEntityInput struct {
g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"`
Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"`
Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"`
Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"`
Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"`
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"`
NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"`
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"`
Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"`
}
cGenPbEntityOutput struct{}
cGenPbEntityInternalInput struct {
cGenPbEntityInput
TableName string // TableName specifies the table name of the table.
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
}
)
const (
cGenPbEntityConfig = `gfcli.gen.pbentity`
cGenPbEntityBrief = `generate entity message files in protobuf3 format`
@ -83,28 +106,6 @@ set it to "none" to ignore json tag generating.
`
)
type (
cGenPbEntityInput struct {
g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"`
Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"`
Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"`
Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"`
Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"`
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"`
NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"`
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"`
Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"`
}
cGenPbEntityOutput struct{}
cGenPbEntityInternalInput struct {
cGenPbEntityInput
TableName string // TableName specifies the table name of the table.
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
}
)
func init() {
gtag.Sets(g.MapStrStr{
`cGenPbEntityConfig`: cGenPbEntityConfig,
@ -124,7 +125,7 @@ func init() {
})
}
func (c cGen) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
func (c cGenPbEntity) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
var (
config = g.Cfg()
)
@ -152,10 +153,10 @@ func doGenPbEntityForArray(ctx context.Context, index int, in cGenPbEntityInput)
if index >= 0 {
err = g.Cfg().MustGet(
ctx,
fmt.Sprintf(`%s.%d`, cGenDaoConfig, index),
fmt.Sprintf(`%s.%d`, cGenPbEntityConfig, index),
).Scan(&in)
if err != nil {
mlog.Fatalf(`invalid configuration of "%s": %+v`, cGenDaoConfig, err)
mlog.Fatalf(`invalid configuration of "%s": %+v`, cGenPbEntityConfig, err)
}
}
if in.Package == "" {

View File

@ -0,0 +1,9 @@
package cmd
import (
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genservice"
)
type (
cGenService = genservice.CGenService
)

View File

@ -10,6 +10,7 @@ import (
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gres"
"github.com/gogf/gf/v2/util/gtag"
)
@ -48,7 +49,8 @@ func init() {
type cInitInput struct {
g.Meta `name:"init"`
Name string `name:"NAME" arg:"true" v:"required" brief:"{cInitNameBrief}"`
Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
Update bool `name:"update" short:"u" brief:"update to the latest goframe version" orphan:"true"`
}
type cInitOutput struct{}
@ -89,6 +91,27 @@ func (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err
return
}
// Update the GoFrame version.
if in.Update {
mlog.Print("update goframe...")
// go get -u github.com/gogf/gf/v2@latest
updateCommand := `go get -u github.com/gogf/gf/v2@latest`
if in.Name != "." {
updateCommand = fmt.Sprintf(`cd %s && %s`, in.Name, updateCommand)
}
if err = gproc.ShellRun(ctx, updateCommand); err != nil {
mlog.Fatal(err)
}
// go mod tidy
gomModTidyCommand := `go mod tidy`
if in.Name != "." {
gomModTidyCommand = fmt.Sprintf(`cd %s && %s`, in.Name, gomModTidyCommand)
}
if err = gproc.ShellRun(ctx, gomModTidyCommand); err != nil {
mlog.Fatal(err)
}
}
mlog.Print("initialization done! ")
if !in.Mono {
enjoyCommand := `gf run main.go`

View File

@ -46,6 +46,7 @@ which compiles and runs the go codes asynchronously when codes change.
cRunFileBrief = `building file path.`
cRunPathBrief = `output directory path for built binary file. it's "manifest/output" in default`
cRunExtraBrief = `the same options as "go run"/"go build" except some options as follows defined`
cRunArgsBrief = `custom arguments for your process`
)
var (
@ -61,6 +62,7 @@ func init() {
`cRunFileBrief`: cRunFileBrief,
`cRunPathBrief`: cRunPathBrief,
`cRunExtraBrief`: cRunExtraBrief,
`cRunArgsBrief`: cRunArgsBrief,
})
}
@ -70,6 +72,7 @@ type (
File string `name:"FILE" arg:"true" brief:"{cRunFileBrief}" v:"required"`
Path string `name:"path" short:"p" brief:"{cRunPathBrief}" d:"./"`
Extra string `name:"extra" short:"e" brief:"{cRunExtraBrief}"`
Args string `name:"args" short:"a" brief:"{cRunArgsBrief}"`
}
cRunOutput struct{}
)
@ -84,6 +87,7 @@ func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err err
File: in.File,
Path: in.Path,
Options: in.Extra,
Args: in.Args,
}
dirty := gtype.NewBool()
_, err = gfsnotify.Add(gfile.RealPath("."), func(event *gfsnotify.Event) {
@ -98,17 +102,17 @@ func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err err
gtimer.SetTimeout(ctx, 1500*gtime.MS, func(ctx context.Context) {
defer dirty.Set(false)
mlog.Printf(`go file changes: %s`, event.String())
app.Run()
app.Run(ctx)
})
})
if err != nil {
mlog.Fatal(err)
}
go app.Run()
go app.Run(ctx)
select {}
}
func (app *cRunApp) Run() {
func (app *cRunApp) Run(ctx context.Context) {
// Rebuild and run the codes.
renamePath := ""
mlog.Printf("build: %s", app.File)
@ -131,7 +135,7 @@ func (app *cRunApp) Run() {
app.File,
)
mlog.Print(buildCommand)
result, err := gproc.ShellExec(buildCommand)
result, err := gproc.ShellExec(ctx, buildCommand)
if err != nil {
mlog.Printf("build error: \n%s%s", result, err.Error())
return
@ -153,7 +157,7 @@ func (app *cRunApp) Run() {
} else {
process = gproc.NewProcessCmd(runCommand, nil)
}
if pid, err := process.Start(); err != nil {
if pid, err := process.Start(ctx); err != nil {
mlog.Printf("build running error: %s", err.Error())
} else {
mlog.Printf("build running pid: %d", pid)

View File

@ -0,0 +1,374 @@
package gendao
import (
"context"
"fmt"
"strings"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
)
const (
CGenDaoConfig = `gfcli.gen.dao`
CGenDaoUsage = `gf gen dao [OPTION]`
CGenDaoBrief = `automatically generate go files for dao/do/entity`
CGenDaoEg = `
gf gen dao
gf gen dao -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
gf gen dao -p ./model -g user-center -t user,user_detail,user_login
gf gen dao -r user_
`
CGenDaoAd = `
CONFIGURATION SUPPORT
Options are also supported by configuration file.
It's suggested using configuration file instead of command line arguments making producing.
The configuration node name is "gfcli.gen.dao", which also supports multiple databases, for example(config.yaml):
gfcli:
gen:
dao:
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
tables: "order,products"
jsonCase: "CamelLower"
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
path: "./my-app"
prefix: "primary_"
tables: "user, userDetail"
`
CGenDaoBriefPath = `directory path for generated files`
CGenDaoBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
CGenDaoBriefTables = `generate models only for given tables, multiple table names separated with ','`
CGenDaoBriefTablesEx = `generate models excluding given tables, multiple table names separated with ','`
CGenDaoBriefPrefix = `add prefix for all table of specified link/database tables`
CGenDaoBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
CGenDaoBriefStdTime = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`
CGenDaoBriefWithTime = `add created time for auto produced go files`
CGenDaoBriefGJsonSupport = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`
CGenDaoBriefImportPrefix = `custom import prefix for generated go files`
CGenDaoBriefDaoPath = `directory path for storing generated dao files under path`
CGenDaoBriefDoPath = `directory path for storing generated do files under path`
CGenDaoBriefEntityPath = `directory path for storing generated entity files under path`
CGenDaoBriefOverwriteDao = `overwrite all dao files both inside/outside internal folder`
CGenDaoBriefModelFile = `custom file name for storing generated model content`
CGenDaoBriefModelFileForDao = `custom file name generating model for DAO operations like Where/Data. It's empty in default`
CGenDaoBriefDescriptionTag = `add comment to description tag for each field`
CGenDaoBriefNoJsonTag = `no json tag will be added for each field`
CGenDaoBriefNoModelComment = `no model comment will be added for each field`
CGenDaoBriefClear = `delete all generated go files that do not exist in database`
CGenDaoBriefGroup = `
specifying the configuration group name of database for generated ORM instance,
it's not necessary and the default value is "default"
`
CGenDaoBriefJsonCase = `
generated json tag case for model struct, cases are as follows:
| Case | Example |
|---------------- |--------------------|
| Camel | AnyKindOfString |
| CamelLower | anyKindOfString | default
| Snake | any_kind_of_string |
| SnakeScreaming | ANY_KIND_OF_STRING |
| SnakeFirstUpper | rgb_code_md5 |
| Kebab | any-kind-of-string |
| KebabScreaming | ANY-KIND-OF-STRING |
`
CGenDaoBriefTplDaoIndexPath = `template file path for dao index file`
CGenDaoBriefTplDaoInternalPath = `template file path for dao internal file`
CGenDaoBriefTplDaoDoPathPath = `template file path for dao do file`
CGenDaoBriefTplDaoEntityPath = `template file path for dao entity file`
tplVarTableName = `{TplTableName}`
tplVarTableNameCamelCase = `{TplTableNameCamelCase}`
tplVarTableNameCamelLowerCase = `{TplTableNameCamelLowerCase}`
tplVarPackageImports = `{TplPackageImports}`
tplVarImportPrefix = `{TplImportPrefix}`
tplVarStructDefine = `{TplStructDefine}`
tplVarColumnDefine = `{TplColumnDefine}`
tplVarColumnNames = `{TplColumnNames}`
tplVarGroupName = `{TplGroupName}`
tplVarDatetimeStr = `{TplDatetimeStr}`
tplVarCreatedAtDatetimeStr = `{TplCreatedAtDatetimeStr}`
)
var (
createdAt = gtime.Now()
)
func init() {
gtag.Sets(g.MapStrStr{
`CGenDaoConfig`: CGenDaoConfig,
`CGenDaoUsage`: CGenDaoUsage,
`CGenDaoBrief`: CGenDaoBrief,
`CGenDaoEg`: CGenDaoEg,
`CGenDaoAd`: CGenDaoAd,
`CGenDaoBriefPath`: CGenDaoBriefPath,
`CGenDaoBriefLink`: CGenDaoBriefLink,
`CGenDaoBriefTables`: CGenDaoBriefTables,
`CGenDaoBriefTablesEx`: CGenDaoBriefTablesEx,
`CGenDaoBriefPrefix`: CGenDaoBriefPrefix,
`CGenDaoBriefRemovePrefix`: CGenDaoBriefRemovePrefix,
`CGenDaoBriefStdTime`: CGenDaoBriefStdTime,
`CGenDaoBriefWithTime`: CGenDaoBriefWithTime,
`CGenDaoBriefDaoPath`: CGenDaoBriefDaoPath,
`CGenDaoBriefDoPath`: CGenDaoBriefDoPath,
`CGenDaoBriefEntityPath`: CGenDaoBriefEntityPath,
`CGenDaoBriefGJsonSupport`: CGenDaoBriefGJsonSupport,
`CGenDaoBriefImportPrefix`: CGenDaoBriefImportPrefix,
`CGenDaoBriefOverwriteDao`: CGenDaoBriefOverwriteDao,
`CGenDaoBriefModelFile`: CGenDaoBriefModelFile,
`CGenDaoBriefModelFileForDao`: CGenDaoBriefModelFileForDao,
`CGenDaoBriefDescriptionTag`: CGenDaoBriefDescriptionTag,
`CGenDaoBriefNoJsonTag`: CGenDaoBriefNoJsonTag,
`CGenDaoBriefNoModelComment`: CGenDaoBriefNoModelComment,
`CGenDaoBriefClear`: CGenDaoBriefClear,
`CGenDaoBriefGroup`: CGenDaoBriefGroup,
`CGenDaoBriefJsonCase`: CGenDaoBriefJsonCase,
`CGenDaoBriefTplDaoIndexPath`: CGenDaoBriefTplDaoIndexPath,
`CGenDaoBriefTplDaoInternalPath`: CGenDaoBriefTplDaoInternalPath,
`CGenDaoBriefTplDaoDoPathPath`: CGenDaoBriefTplDaoDoPathPath,
`CGenDaoBriefTplDaoEntityPath`: CGenDaoBriefTplDaoEntityPath,
})
}
type (
CGenDao struct{}
CGenDaoInput struct {
g.Meta `name:"dao" config:"{CGenDaoConfig}" usage:"{CGenDaoUsage}" brief:"{CGenDaoBrief}" eg:"{CGenDaoEg}" ad:"{CGenDaoAd}"`
Path string `name:"path" short:"p" brief:"{CGenDaoBriefPath}" d:"internal"`
Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"`
Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"`
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"`
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenDaoBriefJsonCase}" d:"CamelLower"`
ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenDaoBriefImportPrefix}"`
DaoPath string `name:"daoPath" short:"d" brief:"{CGenDaoBriefDaoPath}" d:"dao"`
DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenDaoBriefTplDaoEntityPath}"`
StdTime bool `name:"stdTime" short:"s" brief:"{CGenDaoBriefStdTime}" orphan:"true"`
WithTime bool `name:"withTime" short:"w" brief:"{CGenDaoBriefWithTime}" orphan:"true"`
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenDaoBriefGJsonSupport}" orphan:"true"`
OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenDaoBriefOverwriteDao}" orphan:"true"`
DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenDaoBriefDescriptionTag}" orphan:"true"`
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenDaoBriefNoJsonTag}" orphan:"true"`
NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"`
Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
}
CGenDaoOutput struct{}
CGenDaoInternalInput struct {
CGenDaoInput
DB gdb.DB
TableNames []string
NewTableNames []string
ModName string // Module name of current golang project, which is used for import purpose.
}
)
func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput, err error) {
if g.Cfg().Available(ctx) {
v := g.Cfg().MustGet(ctx, CGenDaoConfig)
if v.IsSlice() {
for i := 0; i < len(v.Interfaces()); i++ {
doGenDaoForArray(ctx, i, in)
}
} else {
doGenDaoForArray(ctx, -1, in)
}
} else {
doGenDaoForArray(ctx, -1, in)
}
mlog.Print("done!")
return
}
// doGenDaoForArray implements the "gen dao" command for configuration array.
func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
var (
err error
db gdb.DB
modName string // Go module name, eg: github.com/gogf/gf.
)
if index >= 0 {
err = g.Cfg().MustGet(
ctx,
fmt.Sprintf(`%s.%d`, CGenDaoConfig, index),
).Scan(&in)
if err != nil {
mlog.Fatalf(`invalid configuration of "%s": %+v`, CGenDaoConfig, err)
}
}
if dirRealPath := gfile.RealPath(in.Path); dirRealPath == "" {
mlog.Fatalf(`path "%s" does not exist`, in.Path)
}
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
if in.ImportPrefix == "" {
if !gfile.Exists("go.mod") {
mlog.Fatal("go.mod does not exist in current working directory")
}
var (
goModContent = gfile.GetContents("go.mod")
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
)
if len(match) > 1 {
modName = gstr.Trim(match[1])
} else {
mlog.Fatal("module name does not found in go.mod")
}
}
// It uses user passed database configuration.
if in.Link != "" {
var tempGroup = gtime.TimestampNanoStr()
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
Link: in.Link,
})
if db, err = gdb.Instance(tempGroup); err != nil {
mlog.Fatalf(`database initialization failed: %+v`, err)
}
} else {
db = g.DB(in.Group)
}
if db == nil {
mlog.Fatal(`database initialization failed, may be invalid database configuration`)
}
var tableNames []string
if in.Tables != "" {
tableNames = gstr.SplitAndTrim(in.Tables, ",")
} else {
tableNames, err = db.Tables(context.TODO())
if err != nil {
mlog.Fatalf("fetching tables failed: %+v", err)
}
}
// Table excluding.
if in.TablesEx != "" {
array := garray.NewStrArrayFrom(tableNames)
for _, v := range gstr.SplitAndTrim(in.TablesEx, ",") {
array.RemoveValue(v)
}
tableNames = array.Slice()
}
// Generating dao & model go files one by one according to given table name.
newTableNames := make([]string, len(tableNames))
for i, tableName := range tableNames {
newTableName := tableName
for _, v := range removePrefixArray {
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
}
newTableName = in.Prefix + newTableName
newTableNames[i] = newTableName
}
// Dao: index and internal.
generateDao(ctx, CGenDaoInternalInput{
CGenDaoInput: in,
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ModName: modName,
})
// Do.
generateDo(ctx, CGenDaoInternalInput{
CGenDaoInput: in,
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ModName: modName,
})
// Entity.
generateEntity(ctx, CGenDaoInternalInput{
CGenDaoInput: in,
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ModName: modName,
})
}
func getImportPartContent(source string, isDo bool) string {
var (
packageImportsArray = garray.NewStrArray()
)
if isDo {
packageImportsArray.Append(`"github.com/gogf/gf/v2/frame/g"`)
}
// Time package recognition.
if strings.Contains(source, "gtime.Time") {
packageImportsArray.Append(`"github.com/gogf/gf/v2/os/gtime"`)
} else if strings.Contains(source, "time.Time") {
packageImportsArray.Append(`"time"`)
}
// Json type.
if strings.Contains(source, "gjson.Json") {
packageImportsArray.Append(`"github.com/gogf/gf/v2/encoding/gjson"`)
}
// Generate and write content to golang file.
packageImportsStr := ""
if packageImportsArray.Len() > 0 {
packageImportsStr = fmt.Sprintf("import(\n%s\n)", packageImportsArray.Join("\n"))
}
return packageImportsStr
}
func replaceDefaultVar(in CGenDaoInternalInput, origin string) string {
var tplCreatedAtDatetimeStr string
var tplDatetimeStr string = createdAt.String()
if in.WithTime {
tplCreatedAtDatetimeStr = fmt.Sprintf(`Created at %s`, tplDatetimeStr)
}
return gstr.ReplaceByMap(origin, g.MapStrStr{
tplVarDatetimeStr: tplDatetimeStr,
tplVarCreatedAtDatetimeStr: tplCreatedAtDatetimeStr,
})
}
func sortFieldKeyForDao(fieldMap map[string]*gdb.TableField) []string {
names := make(map[int]string)
for _, field := range fieldMap {
names[field.Index] = field.Name
}
var (
i = 0
j = 0
result = make([]string, len(names))
)
for {
if len(names) == 0 {
break
}
if val, ok := names[i]; ok {
result[j] = val
j++
delete(names, i)
}
i++
}
return result
}
func getTemplateFromPathOrDefault(filePath string, def string) string {
if filePath != "" {
if contents := gfile.GetContents(filePath); contents != "" {
return contents
}
}
return def
}

View File

@ -0,0 +1,23 @@
package gendao
import (
"context"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/os/gfile"
)
func doClear(ctx context.Context, dirPath string) {
files, err := gfile.ScanDirFile(dirPath, "*.go", true)
if err != nil {
mlog.Fatal(err)
}
for _, file := range files {
if utils.IsFileDoNotEdit(file) {
if err = gfile.Remove(file); err != nil {
mlog.Print(err)
}
}
}
}

View File

@ -0,0 +1,227 @@
package gendao
import (
"bytes"
"context"
"fmt"
"strings"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/olekukonko/tablewriter"
)
func generateDao(ctx context.Context, in CGenDaoInternalInput) {
var (
dirPathDao = gfile.Join(in.Path, in.DaoPath)
dirPathDaoInternal = gfile.Join(dirPathDao, "internal")
)
if in.Clear {
doClear(ctx, dirPathDao)
}
for i := 0; i < len(in.TableNames); i++ {
generateDaoSingle(ctx, generateDaoSingleInput{
CGenDaoInternalInput: in,
TableName: in.TableNames[i],
NewTableName: in.NewTableNames[i],
DirPathDao: dirPathDao,
DirPathDaoInternal: dirPathDaoInternal,
})
}
}
type generateDaoSingleInput struct {
CGenDaoInternalInput
TableName string // TableName specifies the table name of the table.
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
DirPathDao string
DirPathDaoInternal string
}
// generateDaoSingle generates the dao and model content of given table.
func generateDaoSingle(ctx context.Context, in generateDaoSingleInput) {
// Generating table data preparing.
fieldMap, err := in.DB.TableFields(ctx, in.TableName)
if err != nil {
mlog.Fatalf(`fetching tables fields failed for table "%s": %+v`, in.TableName, err)
}
var (
dirRealPath = gfile.RealPath(in.Path)
tableNameCamelCase = gstr.CaseCamel(in.NewTableName)
tableNameCamelLowerCase = gstr.CaseCamelLower(in.NewTableName)
tableNameSnakeCase = gstr.CaseSnake(in.NewTableName)
importPrefix = in.ImportPrefix
)
if importPrefix == "" {
if dirRealPath == "" {
dirRealPath = in.Path
importPrefix = dirRealPath
importPrefix = gstr.Trim(dirRealPath, "./")
} else {
importPrefix = gstr.Replace(dirRealPath, gfile.Pwd(), "")
}
importPrefix = gstr.Replace(importPrefix, gfile.Separator, "/")
importPrefix = gstr.Join(g.SliceStr{in.ModName, importPrefix, in.DaoPath}, "/")
importPrefix, _ = gregex.ReplaceString(`\/{2,}`, `/`, gstr.Trim(importPrefix, "/"))
} else {
importPrefix = gstr.Join(g.SliceStr{importPrefix, in.DaoPath}, "/")
}
fileName := gstr.Trim(tableNameSnakeCase, "-_.")
if len(fileName) > 5 && fileName[len(fileName)-5:] == "_test" {
// Add suffix to avoid the table name which contains "_test",
// which would make the go file a testing file.
fileName += "_table"
}
// dao - index
generateDaoIndex(generateDaoIndexInput{
generateDaoSingleInput: in,
TableNameCamelCase: tableNameCamelCase,
TableNameCamelLowerCase: tableNameCamelLowerCase,
ImportPrefix: importPrefix,
FileName: fileName,
})
// dao - internal
generateDaoInternal(generateDaoInternalInput{
generateDaoSingleInput: in,
TableNameCamelCase: tableNameCamelCase,
TableNameCamelLowerCase: tableNameCamelLowerCase,
ImportPrefix: importPrefix,
FileName: fileName,
FieldMap: fieldMap,
})
}
type generateDaoIndexInput struct {
generateDaoSingleInput
TableNameCamelCase string
TableNameCamelLowerCase string
ImportPrefix string
FileName string
}
func generateDaoIndex(in generateDaoIndexInput) {
path := gfile.Join(in.DirPathDao, in.FileName+".go")
if in.OverwriteDao || !gfile.Exists(path) {
indexContent := gstr.ReplaceByMap(
getTemplateFromPathOrDefault(in.TplDaoIndexPath, consts.TemplateGenDaoIndexContent),
g.MapStrStr{
tplVarImportPrefix: in.ImportPrefix,
tplVarTableName: in.TableName,
tplVarTableNameCamelCase: in.TableNameCamelCase,
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
})
indexContent = replaceDefaultVar(in.CGenDaoInternalInput, indexContent)
if err := gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
utils.GoFmt(path)
mlog.Print("generated:", path)
}
}
}
type generateDaoInternalInput struct {
generateDaoSingleInput
TableNameCamelCase string
TableNameCamelLowerCase string
ImportPrefix string
FileName string
FieldMap map[string]*gdb.TableField
}
func generateDaoInternal(in generateDaoInternalInput) {
path := gfile.Join(in.DirPathDaoInternal, in.FileName+".go")
modelContent := gstr.ReplaceByMap(
getTemplateFromPathOrDefault(in.TplDaoInternalPath, consts.TemplateGenDaoInternalContent),
g.MapStrStr{
tplVarImportPrefix: in.ImportPrefix,
tplVarTableName: in.TableName,
tplVarGroupName: in.Group,
tplVarTableNameCamelCase: in.TableNameCamelCase,
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
tplVarColumnDefine: gstr.Trim(generateColumnDefinitionForDao(in.FieldMap)),
tplVarColumnNames: gstr.Trim(generateColumnNamesForDao(in.FieldMap)),
})
modelContent = replaceDefaultVar(in.CGenDaoInternalInput, modelContent)
if err := gfile.PutContents(path, strings.TrimSpace(modelContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
utils.GoFmt(path)
mlog.Print("generated:", path)
}
}
// generateColumnNamesForDao generates and returns the column names assignment content of column struct
// for specified table.
func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField) string {
var (
buffer = bytes.NewBuffer(nil)
array = make([][]string, len(fieldMap))
names = sortFieldKeyForDao(fieldMap)
)
for index, name := range names {
field := fieldMap[name]
array[index] = []string{
" #" + gstr.CaseCamel(field.Name) + ":",
fmt.Sprintf(` #"%s",`, field.Name),
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
namesContent := buffer.String()
// Let's do this hack of table writer for indent!
namesContent = gstr.Replace(namesContent, " #", "")
buffer.Reset()
buffer.WriteString(namesContent)
return buffer.String()
}
// generateColumnDefinitionForDao generates and returns the column names definition for specified table.
func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField) string {
var (
buffer = bytes.NewBuffer(nil)
array = make([][]string, len(fieldMap))
names = sortFieldKeyForDao(fieldMap)
)
for index, name := range names {
var (
field = fieldMap[name]
comment = gstr.Trim(gstr.ReplaceByArray(field.Comment, g.SliceStr{
"\n", " ",
"\r", " ",
}))
)
array[index] = []string{
" #" + gstr.CaseCamel(field.Name),
" # " + "string",
" #" + fmt.Sprintf(`// %s`, comment),
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
defineContent := buffer.String()
// Let's do this hack of table writer for indent!
defineContent = gstr.Replace(defineContent, " #", "")
buffer.Reset()
buffer.WriteString(defineContent)
return buffer.String()
}

View File

@ -0,0 +1,81 @@
package gendao
import (
"context"
"fmt"
"strings"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
)
func generateDo(ctx context.Context, in CGenDaoInternalInput) {
var dirPathDo = gfile.Join(in.Path, in.DoPath)
if in.Clear {
doClear(ctx, dirPathDo)
}
in.NoJsonTag = true
in.DescriptionTag = false
in.NoModelComment = false
// Model content.
for i, tableName := range in.TableNames {
fieldMap, err := in.DB.TableFields(ctx, tableName)
if err != nil {
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", tableName, err)
}
var (
newTableName = in.NewTableNames[i]
doFilePath = gfile.Join(dirPathDo, gstr.CaseSnake(newTableName)+".go")
structDefinition = generateStructDefinition(ctx, generateStructDefinitionInput{
CGenDaoInternalInput: in,
TableName: tableName,
StructName: gstr.CaseCamel(newTableName),
FieldMap: fieldMap,
IsDo: true,
})
)
// replace all types to interface{}.
structDefinition, _ = gregex.ReplaceStringFuncMatch(
"([A-Z]\\w*?)\\s+([\\w\\*\\.]+?)\\s+(//)",
structDefinition,
func(match []string) string {
// If the type is already a pointer/slice/map, it does nothing.
if !gstr.HasPrefix(match[2], "*") && !gstr.HasPrefix(match[2], "[]") && !gstr.HasPrefix(match[2], "map") {
return fmt.Sprintf(`%s interface{} %s`, match[1], match[3])
}
return match[0]
},
)
modelContent := generateDoContent(
in,
tableName,
gstr.CaseCamel(newTableName),
structDefinition,
)
err = gfile.PutContents(doFilePath, strings.TrimSpace(modelContent))
if err != nil {
mlog.Fatalf(`writing content to "%s" failed: %v`, doFilePath, err)
} else {
utils.GoFmt(doFilePath)
mlog.Print("generated:", doFilePath)
}
}
}
func generateDoContent(in CGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string) string {
doContent := gstr.ReplaceByMap(
getTemplateFromPathOrDefault(in.TplDaoDoPath, consts.TemplateGenDaoDoContent),
g.MapStrStr{
tplVarTableName: tableName,
tplVarPackageImports: getImportPartContent(structDefine, true),
tplVarTableNameCamelCase: tableNameCamelCase,
tplVarStructDefine: structDefine,
})
doContent = replaceDefaultVar(in, doContent)
return doContent
}

View File

@ -0,0 +1,63 @@
package gendao
import (
"context"
"strings"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
)
func generateEntity(ctx context.Context, in CGenDaoInternalInput) {
var dirPathEntity = gfile.Join(in.Path, in.EntityPath)
if in.Clear {
doClear(ctx, dirPathEntity)
}
// Model content.
for i, tableName := range in.TableNames {
fieldMap, err := in.DB.TableFields(ctx, tableName)
if err != nil {
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", tableName, err)
}
var (
newTableName = in.NewTableNames[i]
entityFilePath = gfile.Join(dirPathEntity, gstr.CaseSnake(newTableName)+".go")
entityContent = generateEntityContent(
in,
newTableName,
gstr.CaseCamel(newTableName),
generateStructDefinition(ctx, generateStructDefinitionInput{
CGenDaoInternalInput: in,
TableName: tableName,
StructName: gstr.CaseCamel(newTableName),
FieldMap: fieldMap,
IsDo: false,
}),
)
)
err = gfile.PutContents(entityFilePath, strings.TrimSpace(entityContent))
if err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", entityFilePath, err)
} else {
utils.GoFmt(entityFilePath)
mlog.Print("generated:", entityFilePath)
}
}
}
func generateEntityContent(in CGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string) string {
entityContent := gstr.ReplaceByMap(
getTemplateFromPathOrDefault(in.TplDaoEntityPath, consts.TemplateGenDaoEntityContent),
g.MapStrStr{
tplVarTableName: tableName,
tplVarPackageImports: getImportPartContent(structDefine, false),
tplVarTableNameCamelCase: tableNameCamelCase,
tplVarStructDefine: structDefine,
})
entityContent = replaceDefaultVar(in, entityContent)
return entityContent
}

View File

@ -0,0 +1,153 @@
package gendao
import (
"bytes"
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/olekukonko/tablewriter"
)
type generateStructDefinitionInput struct {
CGenDaoInternalInput
TableName string // Table name.
StructName string // Struct name.
FieldMap map[string]*gdb.TableField // Table field map.
IsDo bool // Is generating DTO struct.
}
func generateStructDefinition(ctx context.Context, in generateStructDefinitionInput) string {
buffer := bytes.NewBuffer(nil)
array := make([][]string, len(in.FieldMap))
names := sortFieldKeyForDao(in.FieldMap)
for index, name := range names {
field := in.FieldMap[name]
array[index] = generateStructFieldDefinition(ctx, field, in)
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
stContent := buffer.String()
// Let's do this hack of table writer for indent!
stContent = gstr.Replace(stContent, " #", "")
stContent = gstr.Replace(stContent, "` ", "`")
stContent = gstr.Replace(stContent, "``", "")
buffer.Reset()
buffer.WriteString(fmt.Sprintf("type %s struct {\n", in.StructName))
if in.IsDo {
buffer.WriteString(fmt.Sprintf("g.Meta `orm:\"table:%s, do:true\"`\n", in.TableName))
}
buffer.WriteString(stContent)
buffer.WriteString("}")
return buffer.String()
}
// generateStructFieldForModel generates and returns the attribute definition for specified field.
func generateStructFieldDefinition(
ctx context.Context, field *gdb.TableField, in generateStructDefinitionInput,
) []string {
var (
err error
typeName string
jsonTag = getJsonTagFromCase(field.Name, in.JsonCase)
)
typeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)
if err != nil {
panic(err)
}
switch typeName {
case gdb.LocalTypeDate, gdb.LocalTypeDatetime:
if in.StdTime {
typeName = "time.Time"
} else {
typeName = "*gtime.Time"
}
case gdb.LocalTypeInt64Bytes:
typeName = "int64"
case gdb.LocalTypeUint64Bytes:
typeName = "uint64"
// Special type handle.
case gdb.LocalTypeJson, gdb.LocalTypeJsonb:
if in.GJsonSupport {
typeName = "*gjson.Json"
} else {
typeName = "string"
}
}
var (
tagKey = "`"
result = []string{
" #" + gstr.CaseCamel(field.Name),
" #" + typeName,
}
descriptionTag = gstr.Replace(formatComment(field.Comment), `"`, `\"`)
)
result = append(result, " #"+fmt.Sprintf(tagKey+`json:"%s"`, jsonTag))
result = append(result, " #"+fmt.Sprintf(`description:"%s"`+tagKey, descriptionTag))
result = append(result, " #"+fmt.Sprintf(`// %s`, formatComment(field.Comment)))
for k, v := range result {
if in.NoJsonTag {
v, _ = gregex.ReplaceString(`json:".+"`, ``, v)
}
if !in.DescriptionTag {
v, _ = gregex.ReplaceString(`description:".*"`, ``, v)
}
if in.NoModelComment {
v, _ = gregex.ReplaceString(`//.+`, ``, v)
}
result[k] = v
}
return result
}
// formatComment formats the comment string to fit the golang code without any lines.
func formatComment(comment string) string {
comment = gstr.ReplaceByArray(comment, g.SliceStr{
"\n", " ",
"\r", " ",
})
comment = gstr.Replace(comment, `\n`, " ")
comment = gstr.Trim(comment)
return comment
}
// getJsonTagFromCase call gstr.Case* function to convert the s to specified case.
func getJsonTagFromCase(str, caseStr string) string {
switch gstr.ToLower(caseStr) {
case gstr.ToLower("Camel"):
return gstr.CaseCamel(str)
case gstr.ToLower("CamelLower"):
return gstr.CaseCamelLower(str)
case gstr.ToLower("Kebab"):
return gstr.CaseKebab(str)
case gstr.ToLower("KebabScreaming"):
return gstr.CaseKebabScreaming(str)
case gstr.ToLower("Snake"):
return gstr.CaseSnake(str)
case gstr.ToLower("SnakeFirstUpper"):
return gstr.CaseSnakeFirstUpper(str)
case gstr.ToLower("SnakeScreaming"):
return gstr.CaseSnakeScreaming(str)
}
return str
}

View File

@ -0,0 +1,276 @@
package genservice
import (
"context"
"fmt"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gtag"
)
const (
CGenServiceConfig = `gfcli.gen.service`
CGenServiceUsage = `gf gen service [OPTION]`
CGenServiceBrief = `parse struct and associated functions from packages to generate service go file`
CGenServiceEg = `
gf gen service
gf gen service -f Snake
`
CGenServiceBriefSrcFolder = `source folder path to be parsed. default: internal/logic`
CGenServiceBriefDstFolder = `destination folder path storing automatically generated go files. default: internal/service`
CGenServiceBriefFileNameCase = `
destination file name storing automatically generated go files, cases are as follows:
| Case | Example |
|---------------- |--------------------|
| Lower | anykindofstring |
| Camel | AnyKindOfString |
| CamelLower | anyKindOfString |
| Snake | any_kind_of_string | default
| SnakeScreaming | ANY_KIND_OF_STRING |
| SnakeFirstUpper | rgb_code_md5 |
| Kebab | any-kind-of-string |
| KebabScreaming | ANY-KIND-OF-STRING |
`
CGenServiceBriefWatchFile = `used in file watcher, it re-generates all service go files only if given file is under srcFolder`
CGenServiceBriefStPattern = `regular expression matching struct name for generating service. default: ^s([A-Z]\\\\w+)$`
CGenServiceBriefPackages = `produce go files only for given source packages`
CGenServiceBriefImportPrefix = `custom import prefix to calculate import path for generated importing go file of logic`
CGenServiceBriefClear = `delete all generated go files that are not used any further`
)
func init() {
gtag.Sets(g.MapStrStr{
`CGenServiceConfig`: CGenServiceConfig,
`CGenServiceUsage`: CGenServiceUsage,
`CGenServiceBrief`: CGenServiceBrief,
`CGenServiceEg`: CGenServiceEg,
`CGenServiceBriefSrcFolder`: CGenServiceBriefSrcFolder,
`CGenServiceBriefDstFolder`: CGenServiceBriefDstFolder,
`CGenServiceBriefFileNameCase`: CGenServiceBriefFileNameCase,
`CGenServiceBriefWatchFile`: CGenServiceBriefWatchFile,
`CGenServiceBriefStPattern`: CGenServiceBriefStPattern,
`CGenServiceBriefPackages`: CGenServiceBriefPackages,
`CGenServiceBriefImportPrefix`: CGenServiceBriefImportPrefix,
`CGenServiceBriefClear`: CGenServiceBriefClear,
})
}
type (
CGenService struct{}
CGenServiceInput struct {
g.Meta `name:"service" config:"{CGenServiceConfig}" usage:"{CGenServiceUsage}" brief:"{CGenServiceBrief}" eg:"{CGenServiceEg}"`
SrcFolder string `short:"s" name:"srcFolder" brief:"{CGenServiceBriefSrcFolder}" d:"internal/logic"`
DstFolder string `short:"d" name:"dstFolder" brief:"{CGenServiceBriefDstFolder}" d:"internal/service"`
DstFileNameCase string `short:"f" name:"dstFileNameCase" brief:"{CGenServiceBriefFileNameCase}" d:"Snake"`
WatchFile string `short:"w" name:"watchFile" brief:"{CGenServiceBriefWatchFile}"`
StPattern string `short:"a" name:"stPattern" brief:"{CGenServiceBriefStPattern}" d:"^s([A-Z]\\w+)$"`
Packages []string `short:"p" name:"packages" brief:"{CGenServiceBriefPackages}"`
ImportPrefix string `short:"i" name:"importPrefix" brief:"{CGenServiceBriefImportPrefix}"`
Clear bool `short:"l" name:"clear" brief:"{CGenServiceBriefClear}" orphan:"true"`
}
CGenServiceOutput struct{}
)
const (
genServiceFileLockSeconds = 10
)
func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGenServiceOutput, err error) {
// File lock to avoid multiple processes.
var (
flockFilePath = gfile.Temp("gf.cli.gen.service.lock")
flockContent = gfile.GetContents(flockFilePath)
)
if flockContent != "" {
if gtime.Timestamp()-gconv.Int64(flockContent) < genServiceFileLockSeconds {
// If another "gen service" process is running, it just exits.
mlog.Debug(`another "gen service" process is running, exit`)
return
}
}
defer gfile.Remove(flockFilePath)
_ = gfile.PutContents(flockFilePath, gtime.TimestampStr())
in.SrcFolder = gstr.TrimRight(in.SrcFolder, `\/`)
in.SrcFolder = gstr.Replace(in.SrcFolder, "\\", "/")
in.WatchFile = gstr.TrimRight(in.WatchFile, `\/`)
in.WatchFile = gstr.Replace(in.WatchFile, "\\", "/")
// Watch file handling.
if in.WatchFile != "" {
// It works only if given WatchFile is in SrcFolder.
var (
watchFileDir = gfile.Dir(in.WatchFile)
srcFolderDir = gfile.Dir(watchFileDir)
)
mlog.Debug("watchFileDir:", watchFileDir)
mlog.Debug("logicFolderDir:", srcFolderDir)
if !gstr.HasSuffix(gstr.Replace(srcFolderDir, `\`, `/`), in.SrcFolder) {
mlog.Printf(`ignore watch file "%s", not in source path "%s"`, in.WatchFile, in.SrcFolder)
return
}
var newWorkingDir = gfile.Dir(gfile.Dir(srcFolderDir))
if err = gfile.Chdir(newWorkingDir); err != nil {
mlog.Fatalf(`%+v`, err)
}
mlog.Debug("Chdir:", newWorkingDir)
_ = gfile.Remove(flockFilePath)
var command = fmt.Sprintf(
`%s gen service -packages=%s`,
gfile.SelfName(), gfile.Basename(watchFileDir),
)
err = gproc.ShellRun(ctx, command)
return
}
if !gfile.Exists(in.SrcFolder) {
mlog.Fatalf(`source folder path "%s" does not exist`, in.SrcFolder)
}
if in.ImportPrefix == "" {
if !gfile.Exists("go.mod") {
mlog.Fatal("ImportPrefix is empty and go.mod does not exist in current working directory")
}
var (
goModContent = gfile.GetContents("go.mod")
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
)
if len(match) > 1 {
in.ImportPrefix = fmt.Sprintf(`%s/%s`, gstr.Trim(match[1]), gstr.Replace(in.SrcFolder, `\`, `/`))
}
}
var (
isDirty bool // Temp boolean.
files []string // Temp file array.
fileContent string // Temp file content for handling go file.
initImportSrcPackages []string // Used for generating logic.go.
inputPackages = in.Packages // Custom packages.
dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder)) // Package name for generated go files.
generatedDstFilePathSet = gset.NewStrSet() // All generated file path set.
)
// The first level folders.
srcFolderPaths, err := gfile.ScanDir(in.SrcFolder, "*", false)
if err != nil {
return nil, err
}
for _, srcFolderPath := range srcFolderPaths {
if !gfile.IsDir(srcFolderPath) {
continue
}
// Only retrieve sub files, no recursively.
if files, err = gfile.ScanDir(srcFolderPath, "*.go", false); err != nil {
return nil, err
}
if len(files) == 0 {
continue
}
var (
// StructName => FunctionDefinitions
srcPkgInterfaceMap = make(map[string]*garray.StrArray)
srcImportedPackages = garray.NewSortedStrArray().SetUnique(true)
srcPackageName = gfile.Basename(srcFolderPath)
ok bool
dstFilePath = gfile.Join(in.DstFolder,
c.getDstFileNameCase(srcPackageName, in.DstFileNameCase)+".go",
)
)
generatedDstFilePathSet.Add(dstFilePath)
for _, file := range files {
fileContent = gfile.GetContents(file)
// Calculate imported packages of source go files.
err = c.calculateImportedPackages(fileContent, srcImportedPackages)
if err != nil {
return nil, err
}
// Calculate functions and interfaces for service generating.
err = c.calculateInterfaceFunctions(in, fileContent, srcPkgInterfaceMap, dstPackageName)
if err != nil {
return nil, err
}
}
initImportSrcPackages = append(
initImportSrcPackages,
fmt.Sprintf(`%s/%s`, in.ImportPrefix, srcPackageName),
)
// Ignore source packages if input packages given.
if len(inputPackages) > 0 && !gstr.InArray(inputPackages, srcPackageName) {
mlog.Debugf(
`ignore source package "%s" as it is not in desired packages: %+v`,
srcPackageName, inputPackages,
)
continue
}
// Generating service go file for logic.
if ok, err = c.generateServiceFile(generateServiceFilesInput{
CGenServiceInput: in,
SrcStructFunctions: srcPkgInterfaceMap,
SrcImportedPackages: srcImportedPackages.Slice(),
SrcPackageName: srcPackageName,
DstPackageName: dstPackageName,
DstFilePath: dstFilePath,
}); err != nil {
return
}
if ok {
isDirty = true
}
}
if in.Clear {
files, err = gfile.ScanDirFile(in.DstFolder, "*.go", false)
if err != nil {
return nil, err
}
var relativeFilePath string
for _, file := range files {
relativeFilePath = gstr.SubStrFromR(file, in.DstFolder)
if !generatedDstFilePathSet.Contains(relativeFilePath) && utils.IsFileDoNotEdit(relativeFilePath) {
mlog.Printf(`remove no longer used service file: %s`, relativeFilePath)
if err = gfile.Remove(file); err != nil {
return nil, err
}
}
}
}
if isDirty {
// Generate initialization go file.
if len(initImportSrcPackages) > 0 {
if err = c.generateInitializationFile(in, initImportSrcPackages); err != nil {
return
}
}
// Replace v1 to v2 for GoFrame.
if err = c.replaceGeneratedServiceContentGFV2(in); err != nil {
return nil, err
}
mlog.Printf(`gofmt go files in "%s"`, in.DstFolder)
utils.GoFmt(in.DstFolder)
}
mlog.Print(`done!`)
return
}
func (c CGenService) replaceGeneratedServiceContentGFV2(in CGenServiceInput) (err error) {
return gfile.ReplaceDirFunc(func(path, content string) string {
if gstr.Contains(content, `"github.com/gogf/gf`) && !gstr.Contains(content, `"github.com/gogf/gf/v2`) {
content = gstr.Replace(content, `"github.com/gogf/gf"`, `"github.com/gogf/gf/v2"`)
content = gstr.Replace(content, `"github.com/gogf/gf/`, `"github.com/gogf/gf/v2/`)
return content
}
return content
}, in.DstFolder, "*.go", false)
}

View File

@ -0,0 +1,105 @@
package genservice
import (
"go/parser"
"go/token"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
)
func (c CGenService) calculateImportedPackages(fileContent string, srcImportedPackages *garray.SortedStrArray) (err error) {
f, err := parser.ParseFile(token.NewFileSet(), "", fileContent, parser.ImportsOnly)
if err != nil {
return err
}
for _, s := range f.Imports {
if s.Path != nil {
if s.Name != nil {
// If it has alias, and it is not `_`.
if pkgAlias := s.Name.String(); pkgAlias != "_" {
srcImportedPackages.Add(pkgAlias + " " + s.Path.Value)
}
} else {
// no alias
srcImportedPackages.Add(s.Path.Value)
}
}
}
return nil
}
func (c CGenService) calculateInterfaceFunctions(
in CGenServiceInput, fileContent string, srcPkgInterfaceMap map[string]*garray.StrArray, dstPackageName string,
) (err error) {
var (
ok bool
matches [][]string
srcPkgInterfaceFuncArray *garray.StrArray
)
// calculate struct name and its functions according function definitions.
matches, err = gregex.MatchAllString(`func \((.+?)\) ([\s\S]+?) {`, fileContent)
if err != nil {
return err
}
for _, match := range matches {
var (
structName string
structMatch []string
funcReceiver = gstr.Trim(match[1])
receiverArray = gstr.SplitAndTrim(funcReceiver, " ")
functionHead = gstr.Trim(gstr.Replace(match[2], "\n", ""))
)
if len(receiverArray) > 1 {
structName = receiverArray[1]
} else {
structName = receiverArray[0]
}
structName = gstr.Trim(structName, "*")
// Case of:
// Xxx(\n ctx context.Context, req *v1.XxxReq,\n) -> Xxx(ctx context.Context, req *v1.XxxReq)
functionHead = gstr.Replace(functionHead, `,)`, `)`)
functionHead, _ = gregex.ReplaceString(`\(\s+`, `(`, functionHead)
functionHead, _ = gregex.ReplaceString(`\s{2,}`, ` `, functionHead)
if !gstr.IsLetterUpper(functionHead[0]) {
continue
}
// Match and pick the struct name from receiver.
if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil {
return err
}
if len(structMatch) < 1 {
continue
}
structName = gstr.CaseCamel(structMatch[1])
if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok {
srcPkgInterfaceMap[structName] = garray.NewStrArray()
srcPkgInterfaceFuncArray = srcPkgInterfaceMap[structName]
}
srcPkgInterfaceFuncArray.Append(functionHead)
}
// calculate struct name according type definitions.
matches, err = gregex.MatchAllString(`type (.+) struct\s*{`, fileContent)
if err != nil {
return err
}
for _, match := range matches {
var (
structName string
structMatch []string
)
if structMatch, err = gregex.MatchString(in.StPattern, match[1]); err != nil {
return err
}
if len(structMatch) < 1 {
continue
}
structName = gstr.CaseCamel(structMatch[1])
if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok {
srcPkgInterfaceMap[structName] = garray.NewStrArray()
}
}
return nil
}

View File

@ -0,0 +1,198 @@
package genservice
import (
"fmt"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
)
type generateServiceFilesInput struct {
CGenServiceInput
DstFilePath string // Absolute file path for generated service go file.
SrcStructFunctions map[string]*garray.StrArray
SrcImportedPackages []string
SrcPackageName string
DstPackageName string
}
func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool, err error) {
var (
generatedContent string
allFuncArray = garray.NewStrArray() // Used for check whether interface dirty, going to change file content.
importedPackagesContent = fmt.Sprintf(
"import (\n%s\n)", gstr.Join(in.SrcImportedPackages, "\n"),
)
)
generatedContent += gstr.ReplaceByMap(consts.TemplateGenServiceContentHead, g.MapStrStr{
"{Imports}": importedPackagesContent,
"{PackageName}": in.DstPackageName,
})
// Type definitions.
generatedContent += "type("
generatedContent += "\n"
for structName, funcArray := range in.SrcStructFunctions {
allFuncArray.Append(funcArray.Slice()...)
generatedContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentInterface, g.MapStrStr{
"{InterfaceName}": "I" + structName,
"{FuncDefinition}": funcArray.Join("\n\t"),
}))
generatedContent += "\n"
}
generatedContent += ")"
generatedContent += "\n"
// Generating variable and register definitions.
var (
variableContent string
generatingInterfaceCheck string
)
// Variable definitions.
for structName, _ := range in.SrcStructFunctions {
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
continue
}
variableContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentVariable, g.MapStrStr{
"{StructName}": structName,
"{InterfaceName}": "I" + structName,
}))
variableContent += "\n"
}
if variableContent != "" {
generatedContent += "var("
generatedContent += "\n"
generatedContent += variableContent
generatedContent += ")"
generatedContent += "\n"
}
// Variable register function definitions.
for structName, _ := range in.SrcStructFunctions {
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
continue
}
generatedContent += gstr.Trim(gstr.ReplaceByMap(consts.TemplateGenServiceContentRegister, g.MapStrStr{
"{StructName}": structName,
"{InterfaceName}": "I" + structName,
}))
generatedContent += "\n\n"
}
// Replace empty braces that have new line.
generatedContent, _ = gregex.ReplaceString(`{[\s\t]+}`, `{}`, generatedContent)
// Remove package name calls of `dstPackageName` in produced codes.
generatedContent, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, in.DstPackageName), ``, generatedContent)
// Write file content to disk.
if gfile.Exists(in.DstFilePath) {
if !utils.IsFileDoNotEdit(in.DstFilePath) {
mlog.Printf(`ignore file as it is manually maintained: %s`, in.DstFilePath)
return false, nil
}
if !c.isToGenerateServiceGoFile(in.DstPackageName, in.DstFilePath, allFuncArray) {
mlog.Printf(`not dirty, ignore generating service go file: %s`, in.DstFilePath)
return false, nil
}
}
mlog.Printf(`generating service go file: %s`, in.DstFilePath)
if err = gfile.PutContents(in.DstFilePath, generatedContent); err != nil {
return true, err
}
return true, nil
}
// isToGenerateServiceGoFile checks and returns whether the service content dirty.
func (c CGenService) isToGenerateServiceGoFile(dstPackageName, filePath string, funcArray *garray.StrArray) bool {
var (
fileContent = gfile.GetContents(filePath)
generatedFuncArray = garray.NewSortedStrArrayFrom(funcArray.Slice())
contentFuncArray = garray.NewSortedStrArray()
)
if fileContent == "" {
return true
}
matches, _ := gregex.MatchAllString(`\s+interface\s+{([\s\S]+?)}`, fileContent)
for _, match := range matches {
contentFuncArray.Append(gstr.SplitAndTrim(match[1], "\n")...)
}
if generatedFuncArray.Len() != contentFuncArray.Len() {
mlog.Debugf(
`dirty, generatedFuncArray.Len()[%d] != contentFuncArray.Len()[%d]`,
generatedFuncArray.Len(), contentFuncArray.Len(),
)
return true
}
var funcDefinition string
for i := 0; i < generatedFuncArray.Len(); i++ {
funcDefinition, _ = gregex.ReplaceString(
fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, generatedFuncArray.At(i),
)
if funcDefinition != contentFuncArray.At(i) {
mlog.Debugf(`dirty, %s != %s`, funcDefinition, contentFuncArray.At(i))
return true
}
}
return false
}
func (c CGenService) generateInitializationFile(in CGenServiceInput, importSrcPackages []string) (err error) {
var (
srcPackageName = gstr.ToLower(gfile.Basename(in.SrcFolder))
srcFilePath = gfile.Join(in.SrcFolder, srcPackageName+".go")
srcImports string
generatedContent string
)
if !utils.IsFileDoNotEdit(srcFilePath) {
mlog.Debugf(`ignore file as it is manually maintained: %s`, srcFilePath)
return nil
}
for _, importSrcPackage := range importSrcPackages {
srcImports += fmt.Sprintf(`%s_ "%s"%s`, "\t", importSrcPackage, "\n")
}
generatedContent = gstr.ReplaceByMap(consts.TemplateGenServiceLogicContent, g.MapStrStr{
"{PackageName}": srcPackageName,
"{Imports}": srcImports,
})
mlog.Printf(`generating init go file: %s`, srcFilePath)
if err = gfile.PutContents(srcFilePath, generatedContent); err != nil {
return err
}
utils.GoFmt(srcFilePath)
return nil
}
// getDstFileNameCase call gstr.Case* function to convert the s to specified case.
func (c CGenService) getDstFileNameCase(str, caseStr string) string {
switch gstr.ToLower(caseStr) {
case gstr.ToLower("Lower"):
return gstr.ToLower(str)
case gstr.ToLower("Camel"):
return gstr.CaseCamel(str)
case gstr.ToLower("CamelLower"):
return gstr.CaseCamelLower(str)
case gstr.ToLower("Kebab"):
return gstr.CaseKebab(str)
case gstr.ToLower("KebabScreaming"):
return gstr.CaseKebabScreaming(str)
case gstr.ToLower("SnakeFirstUpper"):
return gstr.CaseSnakeFirstUpper(str)
case gstr.ToLower("SnakeScreaming"):
return gstr.CaseSnakeScreaming(str)
}
return gstr.CaseSnake(str)
}

View File

@ -1 +1,7 @@
package consts
const (
// DoNotEditKey is used in generated files,
// which marks the files will be overwritten by CLI tool.
DoNotEditKey = `DO NOT EDIT`
)

View File

@ -1,6 +1,6 @@
package consts
const TemplateDaoDaoIndexContent = `
const TemplateGenDaoIndexContent = `
// =================================================================================
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
// =================================================================================
@ -31,15 +31,16 @@ var (
`
const TemplateDaoDaoInternalContent = `
const TemplateGenDaoInternalContent = `
// ==========================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT. {TplDatetimeStr}
// Code generated by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr}
// ==========================================================================
package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)
@ -56,7 +57,7 @@ type {TplTableNameCamelCase}Columns struct {
{TplColumnDefine}
}
// {TplTableNameCamelLowerCase}Columns holds the columns for table {TplTableName}.
// {TplTableNameCamelLowerCase}Columns holds the columns for table {TplTableName}.
var {TplTableNameCamelLowerCase}Columns = {TplTableNameCamelCase}Columns{
{TplColumnNames}
}

View File

@ -2,7 +2,7 @@ package consts
const TemplateGenDaoDoContent = `
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT. {TplDatetimeStr}
// Code generated by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr}
// =================================================================================
package do

View File

@ -2,7 +2,7 @@ package consts
const TemplateGenDaoEntityContent = `
// =================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT. {TplDatetimeStr}
// Code generated by GoFrame CLI tool. DO NOT EDIT. {TplCreatedAtDatetimeStr}
// =================================================================================
package entity

View File

@ -0,0 +1,35 @@
package consts
const TemplateGenServiceContentHead = `
// ================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// You can delete these comments if you wish manually maintain this interface file.
// ================================================================================
package {PackageName}
{Imports}
`
const TemplateGenServiceContentInterface = `
{InterfaceName} interface {
{FuncDefinition}
}
`
const TemplateGenServiceContentVariable = `
local{StructName} {InterfaceName}
`
const TemplateGenServiceContentRegister = `
func {StructName}() {InterfaceName} {
if local{StructName} == nil {
panic("implement not found for interface {InterfaceName}, forgot register?")
}
return local{StructName}
}
func Register{StructName}(i {InterfaceName}) {
local{StructName} = i
}
`

View File

@ -0,0 +1,13 @@
package consts
const TemplateGenServiceLogicContent = `
// ==========================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// ==========================================================================
package {PackageName}
import(
{Imports}
)
`

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,18 +1,44 @@
package utils
import (
"fmt"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"golang.org/x/tools/imports"
)
var (
// gofmtPath is the binary path of command `gofmt`.
gofmtPath = gproc.SearchBinaryPath("gofmt")
)
// GoFmt formats the source file using command `gofmt -w -s PATH`.
// GoFmt formats the source file and adds or removes import statements as necessary.
func GoFmt(path string) {
if gofmtPath != "" {
gproc.ShellExec(fmt.Sprintf(`%s -w -s %s`, gofmtPath, path))
replaceFunc := func(path, content string) string {
res, err := imports.Process(path, []byte(content), nil)
if err != nil {
mlog.Printf(`error format "%s" go files: %v`, path, err)
return content
}
return string(res)
}
var err error
if gfile.IsFile(path) {
// File format.
if gfile.ExtName(path) != "go" {
return
}
err = gfile.ReplaceFileFunc(replaceFunc, path)
} else {
// Folder format.
err = gfile.ReplaceDirFunc(replaceFunc, path, "*.go", true)
}
if err != nil {
mlog.Printf(`error format "%s" go files: %v`, path, err)
}
}
// IsFileDoNotEdit checks and returns whether file contains `do not edit` key.
func IsFileDoNotEdit(filePath string) bool {
if !gfile.Exists(filePath) {
return true
}
return gstr.Contains(gfile.GetContents(filePath), consts.DoNotEditKey)
}

View File

@ -14,6 +14,7 @@ import (
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/deepcopy"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
@ -820,3 +821,17 @@ func (a *Array) Walk(f func(value interface{}) interface{}) *Array {
func (a *Array) IsEmpty() bool {
return a.Len() == 0
}
// DeepCopy implements interface for deep copy of current type.
func (a *Array) DeepCopy() interface{} {
if a == nil {
return nil
}
a.mu.RLock()
defer a.mu.RUnlock()
newSlice := make([]interface{}, len(a.array))
for i, v := range a.array {
newSlice[i] = deepcopy.Copy(v)
}
return NewArrayFrom(newSlice, a.mu.IsSafe())
}

View File

@ -799,3 +799,15 @@ func (a *IntArray) Walk(f func(value int) int) *IntArray {
func (a *IntArray) IsEmpty() bool {
return a.Len() == 0
}
// DeepCopy implements interface for deep copy of current type.
func (a *IntArray) DeepCopy() interface{} {
if a == nil {
return nil
}
a.mu.RLock()
defer a.mu.RUnlock()
newSlice := make([]int, len(a.array))
copy(newSlice, a.array)
return NewIntArrayFrom(newSlice, a.mu.IsSafe())
}

View File

@ -812,3 +812,15 @@ func (a *StrArray) Walk(f func(value string) string) *StrArray {
func (a *StrArray) IsEmpty() bool {
return a.Len() == 0
}
// DeepCopy implements interface for deep copy of current type.
func (a *StrArray) DeepCopy() interface{} {
if a == nil {
return nil
}
a.mu.RLock()
defer a.mu.RUnlock()
newSlice := make([]string, len(a.array))
copy(newSlice, a.array)
return NewStrArrayFrom(newSlice, a.mu.IsSafe())
}

View File

@ -12,6 +12,7 @@ import (
"math"
"sort"
"github.com/gogf/gf/v2/internal/deepcopy"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
@ -796,3 +797,17 @@ func (a *SortedArray) getComparator() func(a, b interface{}) int {
}
return a.comparator
}
// DeepCopy implements interface for deep copy of current type.
func (a *SortedArray) DeepCopy() interface{} {
if a == nil {
return nil
}
a.mu.RLock()
defer a.mu.RUnlock()
newSlice := make([]interface{}, len(a.array))
for i, v := range a.array {
newSlice[i] = deepcopy.Copy(v)
}
return NewSortedArrayFrom(newSlice, a.comparator, a.mu.IsSafe())
}

View File

@ -744,3 +744,15 @@ func (a *SortedIntArray) getComparator() func(a, b int) int {
}
return a.comparator
}
// DeepCopy implements interface for deep copy of current type.
func (a *SortedIntArray) DeepCopy() interface{} {
if a == nil {
return nil
}
a.mu.RLock()
defer a.mu.RUnlock()
newSlice := make([]int, len(a.array))
copy(newSlice, a.array)
return NewSortedIntArrayFrom(newSlice, a.mu.IsSafe())
}

View File

@ -757,3 +757,15 @@ func (a *SortedStrArray) getComparator() func(a, b string) int {
}
return a.comparator
}
// DeepCopy implements interface for deep copy of current type.
func (a *SortedStrArray) DeepCopy() interface{} {
if a == nil {
return nil
}
a.mu.RLock()
defer a.mu.RUnlock()
newSlice := make([]string, len(a.array))
copy(newSlice, a.array)
return NewSortedStrArrayFrom(newSlice, a.mu.IsSafe())
}

View File

@ -46,6 +46,8 @@ func ExampleNew() {
a.Set(0, 100)
fmt.Println(a.Slice())
fmt.Println(a.At(0))
// Search item and return its index.
fmt.Println(a.Search(5))
@ -66,6 +68,7 @@ func ExampleNew() {
// false
// [0 1 2 3 4 5 6 7 8 9 10 11]
// [100 1 2 3 4 5 6 7 8 9 10 11]
// 100
// 5
// [1 2 3 4 5 6 7 8 9 10 11]
// [1 2 3 4 5 6 7 8 9 10 11]

View File

@ -54,6 +54,14 @@ func ExampleNewIntArraySize() {
// [10 20 15] 3 5
}
func ExampleNewIntArrayRange() {
s := garray.NewIntArrayRange(1, 5, 1)
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
// Output:
// [1 2 3 4 5] 5 5
}
func ExampleNewIntArrayFrom() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
@ -83,9 +91,12 @@ func ExampleIntArray_Get() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
sGet, sBool := s.Get(3)
fmt.Println(sGet, sBool)
sGet, sBool = s.Get(99)
fmt.Println(sGet, sBool)
// Output:
// 30 true
// 0 false
}
func ExampleIntArray_Set() {

View File

@ -25,9 +25,24 @@ func Test_Array_Basic(t *testing.T) {
array := garray.NewArrayFrom(expect)
array2 := garray.NewArrayFrom(expect)
array3 := garray.NewArrayFrom([]interface{}{})
array4 := garray.NewArrayRange(1, 5, 1)
t.Assert(array.Slice(), expect)
t.Assert(array.Interfaces(), expect)
array.Set(0, 100)
err := array.Set(0, 100)
t.AssertNil(err)
err = array.Set(100, 100)
t.AssertNE(err, nil)
t.Assert(array.IsEmpty(), false)
copyArray := array.DeepCopy()
ca := copyArray.(*garray.Array)
ca.Set(0, 1)
cval, _ := ca.Get(0)
val, _ := array.Get(0)
t.AssertNE(cval, val)
v, ok := array.Get(0)
t.Assert(v, 100)
@ -37,6 +52,10 @@ func Test_Array_Basic(t *testing.T) {
t.Assert(v, 1)
t.Assert(ok, true)
v, ok = array.Get(4)
t.Assert(v, nil)
t.Assert(ok, false)
t.Assert(array.Search(100), 0)
t.Assert(array3.Search(100), -1)
t.Assert(array.Contains(100), true)
@ -71,6 +90,12 @@ func Test_Array_Basic(t *testing.T) {
array.InsertAfter(6, 400)
t.Assert(array.Slice(), []interface{}{100, 200, 2, 2, 3, 300, 4, 400})
t.Assert(array.Clear().Len(), 0)
err = array.InsertBefore(99, 9900)
t.AssertNE(err, nil)
err = array.InsertAfter(99, 9900)
t.AssertNE(err, nil)
t.Assert(array4.String(), "[1,2,3,4,5]")
})
}
@ -99,6 +124,11 @@ func TestArray_Unique(t *testing.T) {
array := garray.NewArrayFrom(expect)
t.Assert(array.Unique().Slice(), []interface{}{1, 2, 3, 4, 5})
})
gtest.C(t, func(t *gtest.T) {
expect := []interface{}{}
array := garray.NewArrayFrom(expect)
t.Assert(array.Unique().Slice(), []interface{}{})
})
}
func TestArray_PushAndPop(t *testing.T) {
@ -382,6 +412,21 @@ func TestArray_Rand(t *testing.T) {
t.Assert(a1.Contains(i1), true)
t.Assert(a1.Len(), 4)
})
gtest.C(t, func(t *gtest.T) {
a1 := []interface{}{}
array1 := garray.NewArrayFrom(a1)
rand, found := array1.Rand()
t.AssertNil(rand)
t.Assert(found, false)
})
gtest.C(t, func(t *gtest.T) {
a1 := []interface{}{}
array1 := garray.NewArrayFrom(a1)
rand := array1.Rands(1)
t.AssertNil(rand)
})
}
func TestArray_Shuffle(t *testing.T) {
@ -412,6 +457,12 @@ func TestArray_Join(t *testing.T) {
array1 := garray.NewArrayFrom(a1)
t.Assert(array1.Join("."), `0.1."a".\a`)
})
gtest.C(t, func(t *gtest.T) {
a1 := []interface{}{}
array1 := garray.NewArrayFrom(a1)
t.Assert(len(array1.Join(".")), 0)
})
}
func TestArray_String(t *testing.T) {
@ -419,6 +470,8 @@ func TestArray_String(t *testing.T) {
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
array1 := garray.NewArrayFrom(a1)
t.Assert(array1.String(), `[0,1,2,3,4,5,6]`)
array1 = nil
t.Assert(array1.String(), "")
})
}

View File

@ -63,6 +63,19 @@ func Test_IntArray_Basic(t *testing.T) {
array.InsertAfter(6, 400)
t.Assert(array.Slice(), []int{100, 200, 1, 2, 3, 300, 4, 400})
t.Assert(array.Clear().Len(), 0)
err := array.InsertBefore(99, 300)
t.AssertNE(err, nil)
err = array.InsertAfter(99, 400)
t.AssertNE(err, nil)
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewIntArrayFrom([]int{0, 1, 2, 3})
copyArray := array.DeepCopy().(*garray.IntArray)
copyArray.Set(0, 1)
cval, _ := copyArray.Get(0)
val, _ := array.Get(0)
t.AssertNE(cval, val)
})
}
@ -89,6 +102,8 @@ func TestIntArray_Unique(t *testing.T) {
expect := []int{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}
array := garray.NewIntArrayFrom(expect)
t.Assert(array.Unique().Slice(), []int{1, 2, 3, 4, 5})
array2 := garray.NewIntArrayFrom([]int{})
t.Assert(array2.Unique().Slice(), []int{})
})
}
@ -374,6 +389,14 @@ func TestIntArray_Rand(t *testing.T) {
v, ok := array1.Rand()
t.AssertIN(v, a1)
t.Assert(ok, true)
array2 := garray.NewIntArrayFrom([]int{})
v, ok = array2.Rand()
t.Assert(v, 0)
t.Assert(ok, false)
intSlices := array2.Rands(1)
t.Assert(intSlices, nil)
})
}
@ -420,6 +443,8 @@ func TestIntArray_String(t *testing.T) {
a1 := []int{0, 1, 2, 3, 4, 5, 6}
array1 := garray.NewIntArrayFrom(a1)
t.Assert(array1.String(), "[0,1,2,3,4,5,6]")
array1 = nil
t.Assert(array1.String(), "")
})
}

View File

@ -34,6 +34,10 @@ func Test_StrArray_Basic(t *testing.T) {
t.Assert(v, 100)
t.Assert(ok, true)
v, ok = array3.Get(0)
t.Assert(v, "")
t.Assert(ok, false)
t.Assert(array.Search("100"), 0)
t.Assert(array.Contains("100"), true)
@ -61,12 +65,28 @@ func Test_StrArray_Basic(t *testing.T) {
t.Assert(array.Clear().Len(), 0)
t.Assert(array2.Slice(), expect)
t.Assert(array3.Search("100"), -1)
err := array.InsertBefore(99, "300")
t.AssertNE(err, nil)
array.InsertAfter(99, "400")
t.AssertNE(err, nil)
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewStrArrayFrom([]string{"0", "1", "2", "3"})
copyArray := array.DeepCopy().(*garray.StrArray)
copyArray.Set(0, "1")
cval, _ := copyArray.Get(0)
val, _ := array.Get(0)
t.AssertNE(cval, val)
})
}
func TestStrArray_ContainsI(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := garray.NewStrArray()
t.Assert(s.Contains("A"), false)
s.Append("a", "b", "C")
t.Assert(s.Contains("A"), false)
t.Assert(s.Contains("a"), true)
@ -94,6 +114,8 @@ func TestStrArray_Unique(t *testing.T) {
expect := []string{"1", "1", "2", "2", "3", "3", "2", "2"}
array := garray.NewStrArrayFrom(expect)
t.Assert(array.Unique().Slice(), []string{"1", "2", "3"})
array1 := garray.NewStrArrayFrom([]string{})
t.Assert(array1.Unique().Slice(), []string{})
})
}
@ -364,6 +386,13 @@ func TestStrArray_Rand(t *testing.T) {
v, ok := array1.Rand()
t.Assert(ok, true)
t.AssertIN(v, a1)
array2 := garray.NewStrArrayFrom([]string{})
v, ok = array2.Rand()
t.Assert(ok, false)
t.Assert(v, "")
strArray := array2.Rands(1)
t.AssertNil(strArray)
})
}
@ -406,6 +435,11 @@ func TestStrArray_Join(t *testing.T) {
array1 := garray.NewStrArrayFrom(a1)
t.Assert(array1.Join("."), `0.1."a".\a`)
})
gtest.C(t, func(t *gtest.T) {
a1 := []string{}
array1 := garray.NewStrArrayFrom(a1)
t.Assert(array1.Join("."), "")
})
}
func TestStrArray_String(t *testing.T) {
@ -413,6 +447,9 @@ func TestStrArray_String(t *testing.T) {
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
array1 := garray.NewStrArrayFrom(a1)
t.Assert(array1.String(), `["0","1","2","3","4","5","6"]`)
array1 = nil
t.Assert(array1.String(), "")
})
}

View File

@ -61,6 +61,18 @@ func TestNewSortedArrayFromCopy(t *testing.T) {
})
}
func TestNewSortedArrayRange(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
func1 := func(v1, v2 interface{}) int {
return gconv.Int(v1) - gconv.Int(v2)
}
array1 := garray.NewSortedArrayRange(1, 5, 1, func1)
t.Assert(array1.Len(), 5)
t.Assert(array1, []interface{}{1, 2, 3, 4, 5})
})
}
func TestSortedArray_SetArray(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
a1 := []interface{}{"a", "f", "c"}
@ -106,10 +118,26 @@ func TestSortedArray_Get(t *testing.T) {
v, ok = array1.Get(1)
t.Assert(v, "c")
t.Assert(ok, true)
v, ok = array1.Get(99)
t.Assert(v, nil)
t.Assert(ok, false)
})
}
func TestSortedArray_At(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
a1 := []interface{}{"a", "f", "c"}
func1 := func(v1, v2 interface{}) int {
return strings.Compare(gconv.String(v1), gconv.String(v2))
}
array1 := garray.NewSortedArrayFrom(a1, func1)
v := array1.At(2)
t.Assert(v, "f")
})
}
func TestSortedArray_Remove(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
a1 := []interface{}{"a", "d", "c", "b"}
@ -461,6 +489,11 @@ func TestSortedArray_Rand(t *testing.T) {
t.Assert(ok, true)
t.AssertIN(i1, []interface{}{"a", "d", "c"})
t.Assert(array1.Len(), 3)
array2 := garray.NewSortedArrayFrom([]interface{}{}, func1)
v, ok := array2.Rand()
t.Assert(ok, false)
t.Assert(v, nil)
})
}
@ -479,6 +512,10 @@ func TestSortedArray_Rands(t *testing.T) {
i1 = array1.Rands(4)
t.Assert(len(i1), 4)
array2 := garray.NewSortedArrayFrom([]interface{}{}, func1)
v := array2.Rands(1)
t.Assert(v, nil)
})
}
@ -498,6 +535,12 @@ func TestSortedArray_Join(t *testing.T) {
array1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)
t.Assert(array1.Join("."), `"a".0.1.\a`)
})
gtest.C(t, func(t *gtest.T) {
a1 := []interface{}{}
array1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)
t.Assert(array1.Join("."), "")
})
}
func TestSortedArray_String(t *testing.T) {
@ -505,6 +548,9 @@ func TestSortedArray_String(t *testing.T) {
a1 := []interface{}{0, 1, "a", "b"}
array1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)
t.Assert(array1.String(), `[0,1,"a","b"]`)
array1 = nil
t.Assert(array1.String(), "")
})
}
@ -541,6 +587,11 @@ func TestSortedArray_Unique(t *testing.T) {
array1.Unique()
t.Assert(array1.Len(), 5)
t.Assert(array1, []interface{}{1, 2, 3, 4, 5})
array2 := garray.NewSortedArrayFrom([]interface{}{}, gutil.ComparatorInt)
array2.Unique()
t.Assert(array2.Len(), 0)
t.Assert(array2, []interface{}{})
})
}
@ -878,3 +929,22 @@ func TestSortedArray_Walk(t *testing.T) {
}), g.Slice{"key-1", "key-2"})
})
}
func TestSortedArray_IsEmpty(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedArrayFrom([]interface{}{}, gutil.ComparatorString)
t.Assert(array.IsEmpty(), true)
})
}
func TestSortedArray_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedArrayFrom([]interface{}{1, 2, 3, 4, 5}, gutil.ComparatorString)
copyArray := array.DeepCopy().(*garray.SortedArray)
array.Add(6)
copyArray.Add(7)
cval, _ := copyArray.Get(5)
val, _ := array.Get(5)
t.AssertNE(cval, val)
})
}

View File

@ -19,6 +19,26 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)
func TestNewSortedIntArrayComparator(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
a1 := []int{0, 3, 2, 1, 4, 5, 6}
array1 := garray.NewSortedIntArrayComparator(func(a, b int) int {
return a - b
}, true)
array1.Append(a1...)
t.Assert(array1.Len(), 7)
t.Assert(array1.Interfaces(), []int{0, 1, 2, 3, 4, 5, 6})
})
}
func TestNewSortedIntArrayRange(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array1 := garray.NewSortedIntArrayRange(1, 5, 1)
t.Assert(array1.Len(), 5)
t.Assert(array1.Interfaces(), []int{1, 2, 3, 4, 5})
})
}
func TestNewSortedIntArrayFrom(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
a1 := []int{0, 3, 2, 1, 4, 5, 6}
@ -37,6 +57,17 @@ func TestNewSortedIntArrayFromCopy(t *testing.T) {
})
}
func TestSortedIntArray_At(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
a1 := []int{0, 3, 2, 1}
array1 := garray.NewSortedIntArrayFrom(a1)
v := array1.At(1)
t.Assert(v, 1)
})
}
func TestSortedIntArray_SetArray(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
a1 := []int{0, 1, 2, 3}
@ -78,6 +109,10 @@ func TestSortedIntArray_Get(t *testing.T) {
v, ok = array1.Get(3)
t.Assert(v, 5)
t.Assert(ok, true)
v, ok = array1.Get(99)
t.Assert(v, 0)
t.Assert(ok, false)
})
}
@ -294,6 +329,9 @@ func TestSortedIntArray_Join(t *testing.T) {
a1 := []int{1, 3, 5}
array1 := garray.NewSortedIntArrayFrom(a1)
t.Assert(array1.Join("."), `1.3.5`)
array2 := garray.NewSortedIntArrayFrom([]int{})
t.Assert(array2.Join("."), "")
})
}
@ -302,6 +340,9 @@ func TestSortedIntArray_String(t *testing.T) {
a1 := []int{1, 3, 5}
array1 := garray.NewSortedIntArrayFrom(a1)
t.Assert(array1.String(), `[1,3,5]`)
array1 = nil
t.Assert(array1.String(), "")
})
}
@ -406,6 +447,11 @@ func TestSortedIntArray_Rand(t *testing.T) {
ns1, ok := array1.Rand()
t.AssertIN(ns1, a1)
t.Assert(ok, true)
array2 := garray.NewSortedIntArrayFrom([]int{})
ns2, ok := array2.Rand()
t.Assert(ns2, 0)
t.Assert(ok, false)
})
}
@ -419,6 +465,10 @@ func TestSortedIntArray_Rands(t *testing.T) {
ns2 := array1.Rands(6)
t.Assert(len(ns2), 6)
array2 := garray.NewSortedIntArrayFrom([]int{})
val := array2.Rands(1)
t.Assert(val, nil)
})
}
@ -450,6 +500,10 @@ func TestSortedIntArray_Unique(t *testing.T) {
array1.Unique()
t.Assert(array1.Len(), 5)
t.Assert(array1, []int{1, 2, 3, 4, 5})
array2 := garray.NewSortedIntArrayFrom([]int{})
array2.Unique()
t.Assert(array2.Len(), 0)
})
}
@ -731,3 +785,22 @@ func TestSortedIntArray_Walk(t *testing.T) {
}), g.Slice{11, 12})
})
}
func TestSortedIntArray_IsEmpty(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedIntArrayFrom([]int{})
t.Assert(array.IsEmpty(), true)
})
}
func TestSortedIntArray_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedIntArrayFrom([]int{1, 2, 3, 4, 5})
copyArray := array.DeepCopy().(*garray.SortedIntArray)
array.Add(6)
copyArray.Add(7)
cval, _ := copyArray.Get(5)
val, _ := array.Get(5)
t.AssertNE(cval, val)
})
}

View File

@ -9,6 +9,7 @@
package garray_test
import (
"github.com/gogf/gf/v2/text/gstr"
"testing"
"time"
@ -19,6 +20,18 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)
func TestNewSortedStrArrayComparator(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
a1 := []string{"a", "d", "c", "b"}
s1 := garray.NewSortedStrArrayComparator(func(a, b string) int {
return gstr.Compare(a, b)
})
s1.Add(a1...)
t.Assert(s1.Len(), 4)
t.Assert(s1, []string{"a", "b", "c", "d"})
})
}
func TestNewSortedStrArrayFrom(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
a1 := []string{"a", "d", "c", "b"}
@ -58,6 +71,9 @@ func TestSortedStrArray_ContainsI(t *testing.T) {
t.Assert(s.Contains("A"), false)
t.Assert(s.Contains("a"), true)
t.Assert(s.ContainsI("A"), true)
s = garray.NewSortedStrArray()
t.Assert(s.Contains("A"), false)
})
}
@ -85,6 +101,10 @@ func TestSortedStrArray_Get(t *testing.T) {
v, ok = array1.Get(0)
t.Assert(v, "a")
t.Assert(ok, true)
v, ok = array1.Get(99)
t.Assert(v, "")
t.Assert(ok, false)
})
}
@ -361,6 +381,11 @@ func TestSortedStrArray_Rand(t *testing.T) {
v, ok := array1.Rand()
t.AssertIN(v, []string{"e", "a", "d"})
t.Assert(ok, true)
array2 := garray.NewSortedStrArrayFrom([]string{})
v, ok = array2.Rand()
t.Assert(v, "")
t.Assert(ok, false)
})
}
@ -375,6 +400,10 @@ func TestSortedStrArray_Rands(t *testing.T) {
s1 = array1.Rands(4)
t.Assert(len(s1), 4)
array2 := garray.NewSortedStrArrayFrom([]string{})
val := array2.Rands(1)
t.Assert(val, nil)
})
}
@ -391,6 +420,11 @@ func TestSortedStrArray_Join(t *testing.T) {
array1 := garray.NewSortedStrArrayFrom(a1)
t.Assert(array1.Join("."), `"b".\c.a`)
})
gtest.C(t, func(t *gtest.T) {
array1 := garray.NewSortedStrArrayFrom([]string{})
t.Assert(array1.Join("."), "")
})
}
func TestSortedStrArray_String(t *testing.T) {
@ -398,6 +432,9 @@ func TestSortedStrArray_String(t *testing.T) {
a1 := []string{"e", "a", "d"}
array1 := garray.NewSortedStrArrayFrom(a1)
t.Assert(array1.String(), `["a","d","e"]`)
array1 = nil
t.Assert(array1.String(), "")
})
}
@ -469,6 +506,11 @@ func TestSortedStrArray_Unique(t *testing.T) {
array1.Unique()
t.Assert(array1.Len(), 3)
t.Assert(array1, []string{"1", "2", "3"})
array2 := garray.NewSortedStrArrayFrom([]string{})
array2.Unique()
t.Assert(array2.Len(), 0)
t.Assert(array2, []string{})
})
}
@ -755,3 +797,15 @@ func TestSortedStrArray_Walk(t *testing.T) {
}), g.Slice{"key-1", "key-2"})
})
}
func TestSortedStrArray_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedStrArrayFrom([]string{"a", "b", "c", "d"})
copyArray := array.DeepCopy().(*garray.SortedStrArray)
array.Add("e")
copyArray.Add("f")
cval, _ := copyArray.Get(4)
val, _ := array.Get(4)
t.AssertNE(cval, val)
})
}

View File

@ -12,6 +12,7 @@ import (
"bytes"
"container/list"
"github.com/gogf/gf/v2/internal/deepcopy"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
"github.com/gogf/gf/v2/util/gconv"
@ -546,3 +547,27 @@ func (l *List) UnmarshalValue(value interface{}) (err error) {
l.PushBacks(array)
return err
}
// DeepCopy implements interface for deep copy of current type.
func (l *List) DeepCopy() interface{} {
if l == nil {
return nil
}
l.mu.RLock()
defer l.mu.RUnlock()
if l.list == nil {
return nil
}
var (
length = l.list.Len()
values = make([]interface{}, length)
)
if length > 0 {
for i, e := 0, l.list.Front(); i < length; i, e = i+1, e.Next() {
values[i] = deepcopy.Copy(e.Value)
}
}
return NewFrom(values, l.mu.IsSafe())
}

View File

@ -755,3 +755,13 @@ func TestList_UnmarshalValue(t *testing.T) {
t.Assert(tlist.List.FrontAll(), []interface{}{1, 2, 3})
})
}
func TestList_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
l := NewFrom([]interface{}{1, 2, "a", `"b"`, `\c`})
copyList := l.DeepCopy()
cl := copyList.(*List)
cl.PopBack()
t.AssertNE(l.Size(), cl.Size())
})
}

View File

@ -8,12 +8,14 @@ package gmap
import (
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/deepcopy"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
"github.com/gogf/gf/v2/util/gconv"
)
// AnyAnyMap wraps map type `map[interface{}]interface{}` and provides more map features.
type AnyAnyMap struct {
mu rwmutex.RWMutex
data map[interface{}]interface{}
@ -72,7 +74,7 @@ func (m *AnyAnyMap) Map() map[interface{}]interface{} {
return data
}
// MapCopy returns a copy of the underlying data of the hash map.
// MapCopy returns a shallow copy of the underlying data of the hash map.
func (m *AnyAnyMap) MapCopy() map[interface{}]interface{} {
m.mu.RLock()
defer m.mu.RUnlock()
@ -497,3 +499,18 @@ func (m *AnyAnyMap) UnmarshalValue(value interface{}) (err error) {
}
return
}
// DeepCopy implements interface for deep copy of current type.
func (m *AnyAnyMap) DeepCopy() interface{} {
if m == nil {
return nil
}
m.mu.RLock()
defer m.mu.RUnlock()
data := make(map[interface{}]interface{}, len(m.data))
for k, v := range m.data {
data[k] = deepcopy.Copy(v)
}
return NewFrom(data, m.mu.IsSafe())
}

View File

@ -9,6 +9,7 @@ package gmap
import (
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/deepcopy"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
@ -499,3 +500,17 @@ func (m *IntAnyMap) UnmarshalValue(value interface{}) (err error) {
}
return
}
// DeepCopy implements interface for deep copy of current type.
func (m *IntAnyMap) DeepCopy() interface{} {
if m == nil {
return nil
}
m.mu.RLock()
defer m.mu.RUnlock()
data := make(map[int]interface{}, len(m.data))
for k, v := range m.data {
data[k] = deepcopy.Copy(v)
}
return NewIntAnyMapFrom(data, m.mu.IsSafe())
}

View File

@ -470,3 +470,17 @@ func (m *IntIntMap) UnmarshalValue(value interface{}) (err error) {
}
return
}
// DeepCopy implements interface for deep copy of current type.
func (m *IntIntMap) DeepCopy() interface{} {
if m == nil {
return nil
}
m.mu.RLock()
defer m.mu.RUnlock()
data := make(map[int]int, len(m.data))
for k, v := range m.data {
data[k] = v
}
return NewIntIntMapFrom(data, m.mu.IsSafe())
}

View File

@ -470,3 +470,17 @@ func (m *IntStrMap) UnmarshalValue(value interface{}) (err error) {
}
return
}
// DeepCopy implements interface for deep copy of current type.
func (m *IntStrMap) DeepCopy() interface{} {
if m == nil {
return nil
}
m.mu.RLock()
defer m.mu.RUnlock()
data := make(map[int]string, len(m.data))
for k, v := range m.data {
data[k] = v
}
return NewIntStrMapFrom(data, m.mu.IsSafe())
}

View File

@ -9,12 +9,14 @@ package gmap
import (
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/deepcopy"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
"github.com/gogf/gf/v2/util/gconv"
)
// StrAnyMap implements map[string]interface{} with RWMutex that has switch.
type StrAnyMap struct {
mu rwmutex.RWMutex
data map[string]interface{}
@ -485,3 +487,17 @@ func (m *StrAnyMap) UnmarshalValue(value interface{}) (err error) {
m.data = gconv.Map(value)
return
}
// DeepCopy implements interface for deep copy of current type.
func (m *StrAnyMap) DeepCopy() interface{} {
if m == nil {
return nil
}
m.mu.RLock()
defer m.mu.RUnlock()
data := make(map[string]interface{}, len(m.data))
for k, v := range m.data {
data[k] = deepcopy.Copy(v)
}
return NewStrAnyMapFrom(data, m.mu.IsSafe())
}

View File

@ -474,3 +474,17 @@ func (m *StrIntMap) UnmarshalValue(value interface{}) (err error) {
}
return
}
// DeepCopy implements interface for deep copy of current type.
func (m *StrIntMap) DeepCopy() interface{} {
if m == nil {
return nil
}
m.mu.RLock()
defer m.mu.RUnlock()
data := make(map[string]int, len(m.data))
for k, v := range m.data {
data[k] = v
}
return NewStrIntMapFrom(data, m.mu.IsSafe())
}

View File

@ -463,3 +463,17 @@ func (m *StrStrMap) UnmarshalValue(value interface{}) (err error) {
m.data = gconv.MapStrStr(value)
return
}
// DeepCopy implements interface for deep copy of current type.
func (m *StrStrMap) DeepCopy() interface{} {
if m == nil {
return nil
}
m.mu.RLock()
defer m.mu.RUnlock()
data := make(map[string]string, len(m.data))
for k, v := range m.data {
data[k] = v
}
return NewStrStrMapFrom(data, m.mu.IsSafe())
}

View File

@ -12,6 +12,7 @@ import (
"github.com/gogf/gf/v2/container/glist"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/deepcopy"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/internal/rwmutex"
@ -590,3 +591,22 @@ func (m *ListMap) UnmarshalValue(value interface{}) (err error) {
}
return
}
// DeepCopy implements interface for deep copy of current type.
func (m *ListMap) DeepCopy() interface{} {
if m == nil {
return nil
}
m.mu.RLock()
defer m.mu.RUnlock()
data := make(map[interface{}]interface{}, len(m.data))
if m.list != nil {
var node *gListMapNode
m.list.IteratorAsc(func(e *glist.Element) bool {
node = e.Value.(*gListMapNode)
data[node.key] = deepcopy.Copy(node.value)
return true
})
}
return NewListMapFrom(data, m.mu.IsSafe())
}

View File

@ -602,8 +602,12 @@ func ExampleAnyAnyMap_String() {
fmt.Println(m.String())
var m1 *gmap.Map = nil
fmt.Println(len(m1.String()))
// Output:
// {"k1":"v1"}
// 0
}
func ExampleAnyAnyMap_MarshalJSON() {

View File

@ -601,8 +601,12 @@ func ExampleIntAnyMap_String() {
fmt.Println(m.String())
var m1 *gmap.IntAnyMap = nil
fmt.Println(len(m1.String()))
// Output:
// {"1":"v1"}
// 0
}
func ExampleIntAnyMap_MarshalJSON() {

View File

@ -529,8 +529,12 @@ func ExampleIntIntMap_String() {
fmt.Println(m.String())
var m1 *gmap.IntIntMap = nil
fmt.Println(len(m1.String()))
// Output:
// {"1":1}
// 0
}
func ExampleIntIntMap_MarshalJSON() {

View File

@ -599,8 +599,12 @@ func ExampleStrAnyMap_String() {
fmt.Println(m.String())
var m1 *gmap.StrAnyMap = nil
fmt.Println(len(m1.String()))
// Output:
// {"k1":"v1"}
// 0
}
func ExampleStrAnyMap_MarshalJSON() {

View File

@ -8,11 +8,10 @@ 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"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/container/gmap"
)
func ExampleStrIntMap_Iterator() {
@ -535,8 +534,12 @@ func ExampleStrIntMap_String() {
fmt.Println(m.String())
var m1 *gmap.StrIntMap = nil
fmt.Println(len(m1.String()))
// Output:
// {"k1":1}
// 0
}
func ExampleStrIntMap_MarshalJSON() {

View File

@ -531,8 +531,12 @@ func ExampleStrStrMap_String() {
fmt.Println(m.String())
var m1 *gmap.StrStrMap = nil
fmt.Println(len(m1.String()))
// Output:
// {"k1":"v1"}
// 0
}
func ExampleStrStrMap_MarshalJSON() {

View File

@ -90,7 +90,7 @@ func ExampleNewFrom() {
}
func ExampleNewHashMap() {
m := gmap.New()
m := gmap.NewHashMap()
m.Set("key1", "val1")
fmt.Println(m)
@ -105,7 +105,7 @@ func ExampleNewHashMapFrom() {
m.Set("key1", "val1")
fmt.Println(m)
n := gmap.NewFrom(m.MapCopy(), true)
n := gmap.NewHashMapFrom(m.MapCopy(), true)
fmt.Println(n)
// Output:

View File

@ -171,6 +171,9 @@ func Test_AnyAnyMap_Merge(t *testing.T) {
m2.Set(2, "2")
m1.Merge(m2)
t.Assert(m1.Map(), map[interface{}]interface{}{1: 1, 2: "2"})
m3 := gmap.NewAnyAnyMapFrom(nil)
m3.Merge(m2)
t.Assert(m3.Map(), m2.Map())
})
}
@ -296,6 +299,10 @@ func Test_AnyAnyMap_Pop(t *testing.T) {
t.AssertNE(k1, k2)
t.AssertNE(v1, v2)
k3, v3 := m.Pop()
t.AssertNil(k3)
t.AssertNil(v3)
})
}
@ -327,6 +334,11 @@ func Test_AnyAnyMap_Pops(t *testing.T) {
t.Assert(kArray.Unique().Len(), 3)
t.Assert(vArray.Unique().Len(), 3)
v := m.Pops(1)
t.AssertNil(v)
v = m.Pops(-1)
t.AssertNil(v)
})
}
@ -365,3 +377,17 @@ func TestAnyAnyMap_UnmarshalValue(t *testing.T) {
t.Assert(v.Map.Get("k2"), "v2")
})
}
func Test_AnyAnyMap_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
"k1": "v1",
"k2": "v2",
})
t.Assert(m.Size(), 2)
n := m.DeepCopy().(*gmap.AnyAnyMap)
n.Set("k1", "val1")
t.AssertNE(m.Get("k1"), n.Get("k1"))
})
}

View File

@ -82,6 +82,12 @@ func Test_IntAnyMap_Basic(t *testing.T) {
m2 := gmap.NewIntAnyMapFrom(map[int]interface{}{1: 1, 2: "2"})
t.Assert(m2.Map(), map[int]interface{}{1: 1, 2: "2"})
})
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntAnyMap(true)
m.Set(1, 1)
t.Assert(m.Map(), map[int]interface{}{1: 1})
})
}
func Test_IntAnyMap_Set_Fun(t *testing.T) {
@ -171,6 +177,9 @@ func Test_IntAnyMap_Merge(t *testing.T) {
m2.Set(2, "2")
m1.Merge(m2)
t.Assert(m1.Map(), map[int]interface{}{1: 1, 2: "2"})
m3 := gmap.NewIntAnyMapFrom(nil)
m3.Merge(m2)
t.Assert(m3.Map(), m2.Map())
})
}
@ -271,6 +280,10 @@ func Test_IntAnyMap_Pop(t *testing.T) {
t.AssertNE(k1, k2)
t.AssertNE(v1, v2)
k3, v3 := m.Pop()
t.Assert(k3, 0)
t.AssertNil(v3)
})
}
@ -302,6 +315,11 @@ func Test_IntAnyMap_Pops(t *testing.T) {
t.Assert(kArray.Unique().Len(), 3)
t.Assert(vArray.Unique().Len(), 3)
v := m.Pops(1)
t.AssertNil(v)
v = m.Pops(-1)
t.AssertNil(v)
})
}
@ -340,3 +358,17 @@ func TestIntAnyMap_UnmarshalValue(t *testing.T) {
t.Assert(v.Map.Get(2), "v2")
})
}
func Test_IntAnyMap_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntAnyMapFrom(g.MapIntAny{
1: "v1",
2: "v2",
})
t.Assert(m.Size(), 2)
n := m.DeepCopy().(*gmap.IntAnyMap)
n.Set(1, "val1")
t.AssertNE(m.Get(1), n.Get(1))
})
}

View File

@ -86,6 +86,12 @@ func Test_IntIntMap_Basic(t *testing.T) {
m2 := gmap.NewIntIntMapFrom(map[int]int{1: 1, 2: 2})
t.Assert(m2.Map(), map[int]int{1: 1, 2: 2})
})
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntIntMap(true)
m.Set(1, 1)
t.Assert(m.Map(), map[int]int{1: 1})
})
}
func Test_IntIntMap_Set_Fun(t *testing.T) {
@ -102,6 +108,11 @@ func Test_IntIntMap_Set_Fun(t *testing.T) {
t.Assert(m.SetIfNotExistFuncLock(2, getInt), false)
t.Assert(m.SetIfNotExistFuncLock(4, getInt), true)
})
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntIntMapFrom(nil)
t.Assert(m.GetOrSetFuncLock(1, getInt), getInt())
})
}
func Test_IntIntMap_Batch(t *testing.T) {
@ -177,6 +188,9 @@ func Test_IntIntMap_Merge(t *testing.T) {
m2.Set(2, 2)
m1.Merge(m2)
t.Assert(m1.Map(), map[int]int{1: 1, 2: 2})
m3 := gmap.NewIntIntMapFrom(nil)
m3.Merge(m2)
t.Assert(m3.Map(), m2.Map())
})
}
@ -277,6 +291,10 @@ func Test_IntIntMap_Pop(t *testing.T) {
t.AssertNE(k1, k2)
t.AssertNE(v1, v2)
k3, v3 := m.Pop()
t.Assert(k3, 0)
t.Assert(v3, 0)
})
}
@ -308,6 +326,11 @@ func Test_IntIntMap_Pops(t *testing.T) {
t.Assert(kArray.Unique().Len(), 3)
t.Assert(vArray.Unique().Len(), 3)
v := m.Pops(1)
t.AssertNil(v)
v = m.Pops(-1)
t.AssertNil(v)
})
}
@ -346,3 +369,17 @@ func TestIntIntMap_UnmarshalValue(t *testing.T) {
t.Assert(v.Map.Get(2), "2")
})
}
func Test_IntIntMap_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntIntMapFrom(g.MapIntInt{
1: 1,
2: 2,
})
t.Assert(m.Size(), 2)
n := m.DeepCopy().(*gmap.IntIntMap)
n.Set(1, 2)
t.AssertNE(m.Get(1), n.Get(1))
})
}

View File

@ -63,6 +63,7 @@ func Test_IntStrMap_Basic(t *testing.T) {
t.Assert(m.Size(), 1)
t.Assert(m.IsEmpty(), false)
t.Assert(m.GetOrSet(1, "a"), "a")
t.Assert(m.GetOrSet(2, "b"), "b")
t.Assert(m.SetIfNotExist(2, "b"), false)
@ -90,6 +91,29 @@ func Test_IntStrMap_Basic(t *testing.T) {
m2 := gmap.NewIntStrMapFrom(map[int]string{1: "a", 2: "b"})
t.Assert(m2.Map(), map[int]string{1: "a", 2: "b"})
})
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMap(true)
m.Set(1, "val1")
t.Assert(m.Map(), map[int]string{1: "val1"})
})
}
func TestIntStrMap_MapStrAny(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMap()
m.GetOrSetFunc(1, getStr)
m.GetOrSetFuncLock(2, getStr)
t.Assert(m.MapStrAny(), g.MapStrAny{"1": "z", "2": "z"})
})
}
func TestIntStrMap_Sets(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMapFrom(nil)
m.Sets(g.MapIntStr{1: "z", 2: "z"})
t.Assert(len(m.Map()), 2)
})
}
func Test_IntStrMap_Set_Fun(t *testing.T) {
@ -97,6 +121,8 @@ func Test_IntStrMap_Set_Fun(t *testing.T) {
m := gmap.NewIntStrMap()
m.GetOrSetFunc(1, getStr)
m.GetOrSetFuncLock(2, getStr)
t.Assert(m.GetOrSetFunc(1, getStr), "z")
t.Assert(m.GetOrSetFuncLock(2, getStr), "z")
t.Assert(m.Get(1), "z")
t.Assert(m.Get(2), "z")
t.Assert(m.SetIfNotExistFunc(1, getStr), false)
@ -105,6 +131,16 @@ func Test_IntStrMap_Set_Fun(t *testing.T) {
t.Assert(m.SetIfNotExistFuncLock(2, getStr), false)
t.Assert(m.SetIfNotExistFuncLock(4, getStr), true)
})
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMapFrom(nil)
t.Assert(m.GetOrSetFuncLock(1, getStr), "z")
})
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMapFrom(nil)
t.Assert(m.SetIfNotExistFuncLock(1, getStr), true)
})
}
func Test_IntStrMap_Batch(t *testing.T) {
@ -176,6 +212,10 @@ func Test_IntStrMap_Merge(t *testing.T) {
m2.Set(2, "b")
m1.Merge(m2)
t.Assert(m1.Map(), map[int]string{1: "a", 2: "b"})
m3 := gmap.NewIntStrMapFrom(nil)
m3.Merge(m2)
t.Assert(m3.Map(), m2.Map())
})
}
@ -275,6 +315,10 @@ func Test_IntStrMap_Pop(t *testing.T) {
t.AssertNE(k1, k2)
t.AssertNE(v1, v2)
k3, v3 := m.Pop()
t.Assert(k3, 0)
t.Assert(v3, "")
})
}
@ -306,6 +350,11 @@ func Test_IntStrMap_Pops(t *testing.T) {
t.Assert(kArray.Unique().Len(), 3)
t.Assert(vArray.Unique().Len(), 3)
v := m.Pops(1)
t.AssertNil(v)
v = m.Pops(-1)
t.AssertNil(v)
})
}
@ -344,3 +393,55 @@ func TestIntStrMap_UnmarshalValue(t *testing.T) {
t.Assert(v.Map.Get(2), "v2")
})
}
func TestIntStrMap_Replace(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMapFrom(g.MapIntStr{
1: "v1",
2: "v2",
3: "v3",
})
t.Assert(m.Get(1), "v1")
t.Assert(m.Get(2), "v2")
t.Assert(m.Get(3), "v3")
m.Replace(g.MapIntStr{
1: "v2",
2: "v3",
3: "v1",
})
t.Assert(m.Get(1), "v2")
t.Assert(m.Get(2), "v3")
t.Assert(m.Get(3), "v1")
})
}
func TestIntStrMap_String(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMapFrom(g.MapIntStr{
1: "v1",
2: "v2",
3: "v3",
})
t.Assert(m.String(), "{\"1\":\"v1\",\"2\":\"v2\",\"3\":\"v3\"}")
m = nil
t.Assert(len(m.String()), 0)
})
}
func Test_IntStrMap_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewIntStrMapFrom(g.MapIntStr{
1: "val1",
2: "val2",
})
t.Assert(m.Size(), 2)
n := m.DeepCopy().(*gmap.IntStrMap)
n.Set(1, "v1")
t.AssertNE(m.Get(1), n.Get(1))
})
}

View File

@ -169,6 +169,10 @@ func Test_StrAnyMap_Merge(t *testing.T) {
m2.Set("b", "2")
m1.Merge(m2)
t.Assert(m1.Map(), map[string]interface{}{"a": 1, "b": "2"})
m3 := gmap.NewStrAnyMapFrom(nil)
m3.Merge(m2)
t.Assert(m3.Map(), m2.Map())
})
}
@ -283,6 +287,10 @@ func Test_StrAnyMap_Pop(t *testing.T) {
t.AssertNE(k1, k2)
t.AssertNE(v1, v2)
k3, v3 := m.Pop()
t.Assert(k3, "")
t.Assert(v3, "")
})
}
@ -314,6 +322,11 @@ func Test_StrAnyMap_Pops(t *testing.T) {
t.Assert(kArray.Unique().Len(), 3)
t.Assert(vArray.Unique().Len(), 3)
v := m.Pops(1)
t.AssertNil(v)
v = m.Pops(-1)
t.AssertNil(v)
})
}
@ -352,3 +365,17 @@ func TestStrAnyMap_UnmarshalValue(t *testing.T) {
t.Assert(v.Map.Get("k2"), "v2")
})
}
func Test_StrAnyMap_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrAnyMapFrom(g.MapStrAny{
"key1": "val1",
"key2": "val2",
})
t.Assert(m.Size(), 2)
n := m.DeepCopy().(*gmap.StrAnyMap)
n.Set("key1", "v1")
t.AssertNE(m.Get("key1"), n.Get("key1"))
})
}

View File

@ -100,6 +100,11 @@ func Test_StrIntMap_Set_Fun(t *testing.T) {
t.Assert(m.SetIfNotExistFuncLock("b", getInt), false)
t.Assert(m.SetIfNotExistFuncLock("d", getInt), true)
})
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrIntMapFrom(nil)
t.Assert(m.GetOrSetFuncLock("a", getInt), 123)
})
}
func Test_StrIntMap_Batch(t *testing.T) {
@ -173,6 +178,9 @@ func Test_StrIntMap_Merge(t *testing.T) {
m2.Set("b", 2)
m1.Merge(m2)
t.Assert(m1.Map(), map[string]int{"a": 1, "b": 2})
m3 := gmap.NewStrIntMapFrom(nil)
m3.Merge(m2)
t.Assert(m3.Map(), m2.Map())
})
}
@ -287,6 +295,10 @@ func Test_StrIntMap_Pop(t *testing.T) {
t.AssertNE(k1, k2)
t.AssertNE(v1, v2)
k3, v3 := m.Pop()
t.Assert(k3, "")
t.Assert(v3, 0)
})
}
@ -318,6 +330,11 @@ func Test_StrIntMap_Pops(t *testing.T) {
t.Assert(kArray.Unique().Len(), 3)
t.Assert(vArray.Unique().Len(), 3)
v := m.Pops(1)
t.AssertNil(v)
v = m.Pops(-1)
t.AssertNil(v)
})
}
@ -356,3 +373,17 @@ func TestStrIntMap_UnmarshalValue(t *testing.T) {
t.Assert(v.Map.Get("k2"), 2)
})
}
func Test_StrIntMap_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrIntMapFrom(g.MapStrInt{
"key1": 1,
"key2": 2,
})
t.Assert(m.Size(), 2)
n := m.DeepCopy().(*gmap.StrIntMap)
n.Set("key1", 2)
t.AssertNE(m.Get("key1"), n.Get("key1"))
})
}

View File

@ -98,6 +98,12 @@ func Test_StrStrMap_Set_Fun(t *testing.T) {
t.Assert(m.SetIfNotExistFuncLock("b", getStr), false)
t.Assert(m.SetIfNotExistFuncLock("d", getStr), true)
})
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrStrMapFrom(nil)
t.Assert(m.GetOrSetFuncLock("b", getStr), "z")
})
}
func Test_StrStrMap_Batch(t *testing.T) {
@ -170,6 +176,9 @@ func Test_StrStrMap_Merge(t *testing.T) {
m2.Set("b", "b")
m1.Merge(m2)
t.Assert(m1.Map(), map[string]string{"a": "a", "b": "b"})
m3 := gmap.NewStrStrMapFrom(nil)
m3.Merge(m2)
t.Assert(m3.Map(), m2.Map())
})
}
@ -284,6 +293,10 @@ func Test_StrStrMap_Pop(t *testing.T) {
t.AssertNE(k1, k2)
t.AssertNE(v1, v2)
k3, v3 := m.Pop()
t.Assert(k3, "")
t.Assert(v3, "")
})
}
@ -315,6 +328,11 @@ func Test_StrStrMap_Pops(t *testing.T) {
t.Assert(kArray.Unique().Len(), 3)
t.Assert(vArray.Unique().Len(), 3)
v := m.Pops(1)
t.AssertNil(v)
v = m.Pops(-1)
t.AssertNil(v)
})
}
@ -353,3 +371,17 @@ func TestStrStrMap_UnmarshalValue(t *testing.T) {
t.Assert(v.Map.Get("k2"), "v2")
})
}
func Test_StrStrMap_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewStrStrMapFrom(g.MapStrStr{
"key1": "val1",
"key2": "val2",
})
t.Assert(m.Size(), 2)
n := m.DeepCopy().(*gmap.StrStrMap)
n.Set("key1", "v1")
t.AssertNE(m.Get("key1"), n.Get("key1"))
})
}

View File

@ -154,6 +154,9 @@ func Test_ListMap_Basic_Merge(t *testing.T) {
m2.Set("key2", "val2")
m1.Merge(m2)
t.Assert(m1.Map(), map[interface{}]interface{}{"key1": "val1", "key2": "val2"})
m3 := gmap.NewListMapFrom(nil)
m3.Merge(m2)
t.Assert(m3.Map(), m2.Map())
})
}
@ -266,6 +269,10 @@ func Test_ListMap_Pop(t *testing.T) {
t.AssertNE(k1, k2)
t.AssertNE(v1, v2)
k3, v3 := m.Pop()
t.AssertNil(k3)
t.AssertNil(v3)
})
}
@ -297,6 +304,11 @@ func Test_ListMap_Pops(t *testing.T) {
t.Assert(kArray.Unique().Len(), 3)
t.Assert(vArray.Unique().Len(), 3)
v := m.Pops(1)
t.AssertNil(v)
v = m.Pops(-1)
t.AssertNil(v)
})
}
@ -335,3 +347,44 @@ func TestListMap_UnmarshalValue(t *testing.T) {
t.Assert(v.Map.Get("2"), "v2")
})
}
func TestListMap_String(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewListMap()
m.Set(1, "")
m.Set(2, "2")
t.Assert(m.String(), "{\"1\":\"\",\"2\":\"2\"}")
m1 := gmap.NewListMapFrom(nil)
t.Assert(m1.String(), "{}")
})
}
func TestListMap_MarshalJSON(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewListMap()
m.Set(1, "")
m.Set(2, "2")
res, err := m.MarshalJSON()
t.Assert(res, []byte("{\"1\":\"\",\"2\":\"2\"}"))
t.AssertNil(err)
m1 := gmap.NewListMapFrom(nil)
res, err = m1.MarshalJSON()
t.Assert(res, []byte("{}"))
t.AssertNil(err)
})
}
func TestListMap_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m := gmap.NewListMap()
m.Set(1, "1")
m.Set(2, "2")
t.Assert(m.Size(), 2)
n := m.DeepCopy().(*gmap.ListMap)
n.Set(1, "val1")
t.AssertNE(m.Get(1), n.Get(1))
})
}

View File

@ -85,6 +85,7 @@ func Test_Gpool(t *testing.T) {
assertIndex = 0
p2.Close()
time.Sleep(3 * time.Second)
t.AssertNE(p2.Put(1), nil)
})
gtest.C(t, func(t *gtest.T) {
@ -95,4 +96,27 @@ func Test_Gpool(t *testing.T) {
t.Assert(err3, errors.New("pool is empty"))
t.Assert(v3, nil)
})
gtest.C(t, func(t *gtest.T) {
p := gpool.New(time.Millisecond*200, nil, func(i interface{}) {})
p.Put(1)
time.Sleep(time.Millisecond * 100)
p.Put(2)
time.Sleep(time.Millisecond * 200)
})
gtest.C(t, func(t *gtest.T) {
s := make([]int, 0)
p := gpool.New(time.Millisecond*200, nil, func(i interface{}) {
s = append(s, i.(int))
})
for i := 0; i < 5; i++ {
p.Put(i)
time.Sleep(time.Millisecond * 50)
}
val, err := p.Get()
t.Assert(val, 2)
t.AssertNil(err)
t.Assert(p.Size(), 2)
})
}

View File

@ -62,4 +62,12 @@ func TestQueue_Close(t *testing.T) {
t.Assert(q1.Len(), 2)
q1.Close()
})
gtest.C(t, func(t *gtest.T) {
q1 := gqueue.New(2)
q1.Push(1)
q1.Push(2)
time.Sleep(time.Millisecond)
t.Assert(q1.Len(), 2)
q1.Close()
})
}

View File

@ -183,3 +183,43 @@ func Test_Issue1394(t *testing.T) {
})
}
func TestRing_RLockIteratorNext(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
r := gring.New(10)
for i := 0; i < 10; i++ {
r.Set(i).Next()
}
iterVal := 0
r.RLockIteratorNext(func(value interface{}) bool {
if value.(int) == 0 {
iterVal = value.(int)
return false
}
return true
})
t.Assert(iterVal, 0)
})
}
func TestRing_RLockIteratorPrev(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
r := gring.New(10)
for i := 0; i < 10; i++ {
r.Set(i).Next()
}
iterVal := 0
r.RLockIteratorPrev(func(value interface{}) bool {
if value.(int) == 0 {
iterVal = value.(int)
return false
}
return true
})
t.Assert(iterVal, 0)
})
}

View File

@ -510,3 +510,17 @@ func (set *Set) UnmarshalValue(value interface{}) (err error) {
}
return
}
// DeepCopy implements interface for deep copy of current type.
func (set *Set) DeepCopy() interface{} {
if set == nil {
return nil
}
set.mu.RLock()
defer set.mu.RUnlock()
data := make([]interface{}, 0)
for k, _ := range set.data {
data = append(data, k)
}
return NewFrom(data, set.mu.IsSafe())
}

View File

@ -469,3 +469,21 @@ func (set *IntSet) UnmarshalValue(value interface{}) (err error) {
}
return
}
// DeepCopy implements interface for deep copy of current type.
func (set *IntSet) DeepCopy() interface{} {
if set == nil {
return nil
}
set.mu.RLock()
defer set.mu.RUnlock()
var (
slice = make([]int, len(set.data))
index = 0
)
for k := range set.data {
slice[index] = k
index++
}
return NewIntSetFrom(slice, set.mu.IsSafe())
}

View File

@ -228,6 +228,7 @@ func (set *StrSet) String() string {
i = 0
buffer = bytes.NewBuffer(nil)
)
buffer.WriteByte('[')
for k, _ := range set.data {
buffer.WriteString(`"` + gstr.QuoteMeta(k, `"\`) + `"`)
if i != l-1 {
@ -235,6 +236,7 @@ func (set *StrSet) String() string {
}
i++
}
buffer.WriteByte(']')
return buffer.String()
}
@ -497,3 +499,21 @@ func (set *StrSet) UnmarshalValue(value interface{}) (err error) {
}
return
}
// DeepCopy implements interface for deep copy of current type.
func (set *StrSet) DeepCopy() interface{} {
if set == nil {
return nil
}
set.mu.RLock()
defer set.mu.RUnlock()
var (
slice = make([]string, len(set.data))
index = 0
)
for k := range set.data {
slice[index] = k
index++
}
return NewStrSetFrom(slice, set.mu.IsSafe())
}

View File

@ -126,11 +126,16 @@ func TestSet_Equal(t *testing.T) {
s1 := gset.NewSet()
s2 := gset.NewSet()
s3 := gset.NewSet()
s4 := gset.NewSet()
s1.Add(1, 2, 3)
s2.Add(1, 2, 3)
s3.Add(1, 2, 3, 4)
s4.Add(4, 5, 6)
t.Assert(s1.Equal(s2), true)
t.Assert(s1.Equal(s3), false)
t.Assert(s1.Equal(s4), false)
s5 := s1
t.Assert(s1.Equal(s5), true)
})
}
@ -147,6 +152,9 @@ func TestSet_IsSubsetOf(t *testing.T) {
t.Assert(s1.IsSubsetOf(s3), true)
t.Assert(s2.IsSubsetOf(s1), false)
t.Assert(s3.IsSubsetOf(s2), false)
s4 := s1
t.Assert(s1.IsSubsetOf(s4), true)
})
}
@ -175,6 +183,13 @@ func TestSet_Diff(t *testing.T) {
t.Assert(s3.Contains(2), true)
t.Assert(s3.Contains(3), false)
t.Assert(s3.Contains(4), false)
s4 := s1
s5 := s1.Diff(s2, s4)
t.Assert(s5.Contains(1), true)
t.Assert(s5.Contains(2), true)
t.Assert(s5.Contains(3), false)
t.Assert(s5.Contains(4), false)
})
}
@ -247,6 +262,10 @@ func TestSet_Join(t *testing.T) {
t.Assert(strings.Contains(str1, `\c`), true)
t.Assert(strings.Contains(str1, `a`), true)
})
gtest.C(t, func(t *gtest.T) {
s1 := gset.Set{}
t.Assert(s1.Join(","), "")
})
}
func TestSet_String(t *testing.T) {
@ -257,6 +276,13 @@ func TestSet_String(t *testing.T) {
t.Assert(strings.Contains(str1, "["), true)
t.Assert(strings.Contains(str1, "]"), true)
t.Assert(strings.Contains(str1, "a2"), true)
s1 = nil
t.Assert(s1.String(), "")
s2 := gset.New()
s2.Add(1)
t.Assert(s2.String(), "[1]")
})
}
@ -285,6 +311,7 @@ func TestSet_Sum(t *testing.T) {
func TestSet_Pop(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.New(true)
t.Assert(s.Pop(), nil)
s.Add(1, 2, 3, 4)
t.Assert(s.Size(), 4)
t.AssertIN(s.Pop(), []int{1, 2, 3, 4})
@ -354,6 +381,7 @@ func TestSet_AddIfNotExist(t *testing.T) {
t.Assert(s.AddIfNotExist(2), true)
t.Assert(s.Contains(2), true)
t.Assert(s.AddIfNotExist(2), false)
t.Assert(s.AddIfNotExist(nil), false)
t.Assert(s.Contains(2), true)
})
}
@ -370,6 +398,7 @@ func TestSet_AddIfNotExistFunc(t *testing.T) {
t.Assert(s.Contains(2), true)
t.Assert(s.AddIfNotExistFunc(2, func() bool { return true }), false)
t.Assert(s.Contains(2), true)
t.Assert(s.AddIfNotExistFunc(nil, func() bool { return false }), false)
})
gtest.C(t, func(t *gtest.T) {
s := gset.New(true)
@ -386,6 +415,10 @@ func TestSet_AddIfNotExistFunc(t *testing.T) {
s.Add(1)
wg.Wait()
})
gtest.C(t, func(t *gtest.T) {
s := gset.Set{}
t.Assert(s.AddIfNotExistFunc(1, func() bool { return true }), true)
})
}
func TestSet_Walk(t *testing.T) {
@ -424,6 +457,12 @@ func TestSet_AddIfNotExistFuncLock(t *testing.T) {
}()
wg.Wait()
})
gtest.C(t, func(t *gtest.T) {
s := gset.New(true)
t.Assert(s.AddIfNotExistFuncLock(nil, func() bool { return true }), false)
s1 := gset.Set{}
t.Assert(s1.AddIfNotExistFuncLock(1, func() bool { return true }), true)
})
}
func TestSet_UnmarshalValue(t *testing.T) {
@ -462,3 +501,18 @@ func TestSet_UnmarshalValue(t *testing.T) {
t.Assert(v.Set.Contains("k4"), false)
})
}
func TestSet_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
set := gset.New()
set.Add(1, 2, 3)
copySet := set.DeepCopy().(*gset.Set)
copySet.Add(4)
t.AssertNE(set.Size(), copySet.Size())
t.AssertNE(set.String(), copySet.String())
set = nil
t.AssertNil(set.DeepCopy())
})
}

View File

@ -106,11 +106,16 @@ func TestIntSet_Equal(t *testing.T) {
s1 := gset.NewIntSet()
s2 := gset.NewIntSet()
s3 := gset.NewIntSet()
s4 := gset.NewIntSet()
s1.Add(1, 2, 3)
s2.Add(1, 2, 3)
s3.Add(1, 2, 3, 4)
s4.Add(4, 5, 6)
t.Assert(s1.Equal(s2), true)
t.Assert(s1.Equal(s3), false)
t.Assert(s1.Equal(s4), false)
s5 := s1
t.Assert(s1.Equal(s5), true)
})
}
@ -127,6 +132,9 @@ func TestIntSet_IsSubsetOf(t *testing.T) {
t.Assert(s1.IsSubsetOf(s3), true)
t.Assert(s2.IsSubsetOf(s1), false)
t.Assert(s3.IsSubsetOf(s2), false)
s4 := s1
t.Assert(s1.IsSubsetOf(s4), true)
})
}
@ -155,6 +163,13 @@ func TestIntSet_Diff(t *testing.T) {
t.Assert(s3.Contains(2), true)
t.Assert(s3.Contains(3), false)
t.Assert(s3.Contains(4), false)
s4 := s1
s5 := s1.Diff(s2, s4)
t.Assert(s5.Contains(1), true)
t.Assert(s5.Contains(2), true)
t.Assert(s5.Contains(3), false)
t.Assert(s5.Contains(4), false)
})
}
@ -212,6 +227,7 @@ func TestIntSet_Merge(t *testing.T) {
func TestIntSet_Join(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewIntSet()
t.Assert(s1.Join(","), "")
s1.Add(1, 2, 3)
s3 := s1.Join(",")
t.Assert(strings.Contains(s3, "1"), true)
@ -230,6 +246,8 @@ func TestIntSet_String(t *testing.T) {
t.Assert(strings.Contains(s3, "1"), true)
t.Assert(strings.Contains(s3, "2"), true)
t.Assert(strings.Contains(s3, "3"), true)
s1 = nil
t.Assert(s1.String(), "")
})
}
@ -248,6 +266,7 @@ func TestIntSet_Sum(t *testing.T) {
func TestIntSet_Pop(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s := gset.NewIntSet()
t.Assert(s.Pop(), 0)
s.Add(4, 2, 3)
t.Assert(s.Size(), 3)
t.AssertIN(s.Pop(), []int{4, 2, 3})
@ -291,6 +310,10 @@ func TestIntSet_AddIfNotExist(t *testing.T) {
t.Assert(s.AddIfNotExist(2), false)
t.Assert(s.Contains(2), true)
})
gtest.C(t, func(t *gtest.T) {
s := gset.IntSet{}
t.Assert(s.AddIfNotExist(1), true)
})
}
func TestIntSet_AddIfNotExistFunc(t *testing.T) {
@ -321,6 +344,10 @@ func TestIntSet_AddIfNotExistFunc(t *testing.T) {
s.Add(1)
wg.Wait()
})
gtest.C(t, func(t *gtest.T) {
s := gset.IntSet{}
t.Assert(s.AddIfNotExistFunc(1, func() bool { return true }), true)
})
}
func TestIntSet_AddIfNotExistFuncLock(t *testing.T) {
@ -346,6 +373,10 @@ func TestIntSet_AddIfNotExistFuncLock(t *testing.T) {
}()
wg.Wait()
})
gtest.C(t, func(t *gtest.T) {
s := gset.IntSet{}
t.Assert(s.AddIfNotExistFuncLock(1, func() bool { return true }), true)
})
}
func TestIntSet_Json(t *testing.T) {
@ -426,3 +457,18 @@ func TestIntSet_UnmarshalValue(t *testing.T) {
t.Assert(v.Set.Contains(4), false)
})
}
func TestIntSet_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
set := gset.NewIntSet()
set.Add(1, 2, 3)
copySet := set.DeepCopy().(*gset.IntSet)
copySet.Add(4)
t.AssertNE(set.Size(), copySet.Size())
t.AssertNE(set.String(), copySet.String())
set = nil
t.AssertNil(set.DeepCopy())
})
}

View File

@ -69,6 +69,7 @@ func TestStrSet_ContainsI(t *testing.T) {
t.Assert(s.Contains("A"), false)
t.Assert(s.Contains("a"), true)
t.Assert(s.ContainsI("A"), true)
t.Assert(s.ContainsI("d"), false)
})
}
@ -116,11 +117,16 @@ func TestStrSet_Equal(t *testing.T) {
s1 := gset.NewStrSet()
s2 := gset.NewStrSet()
s3 := gset.NewStrSet()
s4 := gset.NewStrSet()
s1.Add("1", "2", "3")
s2.Add("1", "2", "3")
s3.Add("1", "2", "3", "4")
s4.Add("4", "5", "6")
t.Assert(s1.Equal(s2), true)
t.Assert(s1.Equal(s3), false)
t.Assert(s1.Equal(s4), false)
s5 := s1
t.Assert(s1.Equal(s5), true)
})
}
@ -137,6 +143,9 @@ func TestStrSet_IsSubsetOf(t *testing.T) {
t.Assert(s1.IsSubsetOf(s3), true)
t.Assert(s2.IsSubsetOf(s1), false)
t.Assert(s3.IsSubsetOf(s2), false)
s4 := s1
t.Assert(s1.IsSubsetOf(s4), true)
})
}
@ -165,6 +174,13 @@ func TestStrSet_Diff(t *testing.T) {
t.Assert(s3.Contains("2"), true)
t.Assert(s3.Contains("3"), false)
t.Assert(s3.Contains("4"), false)
s4 := s1
s5 := s1.Diff(s2, s4)
t.Assert(s5.Contains("1"), true)
t.Assert(s5.Contains("2"), true)
t.Assert(s5.Contains("3"), false)
t.Assert(s5.Contains("4"), false)
})
}
@ -239,6 +255,7 @@ func TestStrSet_Join(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
s1 := gset.NewStrSet()
t.Assert(s1.Join(","), "")
s1.Add("a", `"b"`, `\c`)
str1 := s1.Join(",")
t.Assert(strings.Contains(str1, `"b"`), true)
@ -253,6 +270,8 @@ func TestStrSet_String(t *testing.T) {
str1 := s1.String()
t.Assert(strings.Contains(str1, "b"), true)
t.Assert(strings.Contains(str1, "d"), false)
s1 = nil
t.Assert(s1.String(), "")
})
gtest.C(t, func(t *gtest.T) {
@ -300,6 +319,9 @@ func TestStrSet_Pop(t *testing.T) {
t.Assert(s.Size(), 3)
t.AssertIN(s.Pop(), a)
t.Assert(s.Size(), 2)
s1 := gset.StrSet{}
t.Assert(s1.Pop(), "")
})
}
@ -337,6 +359,10 @@ func TestStrSet_AddIfNotExist(t *testing.T) {
t.Assert(s.AddIfNotExist("2"), false)
t.Assert(s.Contains("2"), true)
})
gtest.C(t, func(t *gtest.T) {
s := gset.StrSet{}
t.Assert(s.AddIfNotExist("1"), true)
})
}
func TestStrSet_AddIfNotExistFunc(t *testing.T) {
@ -367,6 +393,10 @@ func TestStrSet_AddIfNotExistFunc(t *testing.T) {
s.Add("1")
wg.Wait()
})
gtest.C(t, func(t *gtest.T) {
s := gset.StrSet{}
t.Assert(s.AddIfNotExistFunc("1", func() bool { return true }), true)
})
}
func TestStrSet_AddIfNotExistFuncLock(t *testing.T) {
@ -392,6 +422,10 @@ func TestStrSet_AddIfNotExistFuncLock(t *testing.T) {
}()
wg.Wait()
})
gtest.C(t, func(t *gtest.T) {
s := gset.StrSet{}
t.Assert(s.AddIfNotExistFuncLock("1", func() bool { return true }), true)
})
}
func TestStrSet_Json(t *testing.T) {
@ -477,3 +511,18 @@ func TestStrSet_UnmarshalValue(t *testing.T) {
t.Assert(v.Set.Contains("4"), false)
})
}
func TestStrSet_DeepCopy(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
set := gset.NewStrSet()
set.Add("1", "2", "3")
copySet := set.DeepCopy().(*gset.StrSet)
copySet.Add("4")
t.AssertNE(set.Size(), copySet.Size())
t.AssertNE(set.String(), copySet.String())
set = nil
t.AssertNil(set.DeepCopy())
})
}

View File

@ -96,3 +96,11 @@ func (v *Bool) UnmarshalValue(value interface{}) error {
v.Set(gconv.Bool(value))
return nil
}
// DeepCopy implements interface for deep copy of current type.
func (v *Bool) DeepCopy() interface{} {
if v == nil {
return nil
}
return NewBool(v.Val())
}

View File

@ -75,3 +75,11 @@ func (v *Byte) UnmarshalValue(value interface{}) error {
v.Set(gconv.Byte(value))
return nil
}
// DeepCopy implements interface for deep copy of current type.
func (v *Byte) DeepCopy() interface{} {
if v == nil {
return nil
}
return NewByte(v.Val())
}

View File

@ -30,7 +30,7 @@ func NewBytes(value ...[]byte) *Bytes {
return t
}
// Clone clones and returns a new concurrent-safe object for []byte type.
// Clone clones and returns a new shallow copy object for []byte type.
func (v *Bytes) Clone() *Bytes {
return NewBytes(v.Val())
}
@ -83,3 +83,14 @@ func (v *Bytes) UnmarshalValue(value interface{}) error {
v.Set(gconv.Bytes(value))
return nil
}
// DeepCopy implements interface for deep copy of current type.
func (v *Bytes) DeepCopy() interface{} {
if v == nil {
return nil
}
oldBytes := v.Val()
newBytes := make([]byte, len(oldBytes))
copy(newBytes, oldBytes)
return NewBytes(newBytes)
}

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