Compare commits

..

128 Commits

Author SHA1 Message Date
d2c1d773db Merge branch 'master' of https://github.com/gogf/gf 2022-07-12 14:08:56 +08:00
e3665cedaf new version v2.1.2 (#1993) 2022-07-12 14:08:19 +08:00
d957102769 v2.1.2 2022-07-12 12:01:00 +08:00
3f40000000 Merge branch 'master' of https://github.com/gogf/gf 2022-07-12 12:00:43 +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
d7229c6843 go mod tidy 2022-07-07 21:45:28 +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
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
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
cb27f26e64 Merge branch 'gogf:master' into master 2022-05-13 22:00:49 +08:00
cf57ea3ef0 Merge branch 'gogf:master' into master 2022-05-13 21:51:08 +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
9fcd3374c1 Merge pull request #1827 from wenzi1/feature/mssql
Feature/mssql
2022-05-12 11:47:28 +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
72b58ff8a1 add unit test 2022-05-12 00:03:20 +08:00
900e0b2751 add gini 2022-05-12 00:00:36 +08:00
351 changed files with 24983 additions and 3505 deletions

95
.github/workflows/docker-compose.yml vendored Normal file
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

View File

@ -6,17 +6,20 @@ on:
branches:
- master
- develop
- personal/**
- feature/**
- fix/**
pull_request:
branches:
- master
- develop
- personal/**
- feature/**
- fix/**
env:
GF_DEBUG: 0
TZ: "Asia/Shanghai"
jobs:
@ -27,7 +30,7 @@ jobs:
services:
# Redis backend server.
redis:
image : redis
image : loads/redis:latest
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
@ -39,7 +42,7 @@ jobs:
# MySQL backend server.
mysql:
image: mysql:5.7
image: loads/mysql:5.7
env:
MYSQL_DATABASE : test
MYSQL_ROOT_PASSWORD: 12345678
@ -49,10 +52,10 @@ jobs:
# PostgreSQL backend server.
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:
@ -66,7 +69,7 @@ jobs:
# MSSQL backend server.
mssql:
image: mcmoe/mssqldocker:latest
image: loads/mssqldocker:latest
env:
ACCEPT_EULA: Y
SA_PASSWORD: LoremIpsum86
@ -84,16 +87,35 @@ jobs:
# ClickHouse backend server.
clickhouse-server:
image: yandex/clickhouse-server
image: loads/clickhouse-server:latest
ports:
- 9000:9000
- 8123:8123
- 9001:9001
polaris:
image: polarismesh/polaris-server-standalone:latest
ports:
- 8090:8090
- 8091:8091
#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
strategy:
matrix:
go: ["1.15", "1.16", "1.17"]
go: [ "1.15", "1.16", "1.17" ]
goarch: [ "386", "amd64" ]
steps:
@ -110,6 +132,9 @@ jobs:
with:
go-version: ${{ matrix.go }}
- name: Start containers
run: docker-compose -f ".github/workflows/docker-compose.yml" up -d --build
- name: Before Script
run: |
find . -name "*.go" | xargs gofmt -w
@ -117,47 +142,33 @@ jobs:
echo "gofmt check pass."
sudo echo "127.0.0.1 local" | sudo tee -a /etc/hosts
- name: CLI Build & Test
- name: Build & Test
run: |
cd cmd/gf
go mod tidy
go build ./...
GOARCH=386 go test -v ./... || exit 1
GOARCH=amd64 go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1
- name: Example Build & Test
run: |
cd example
go mod tidy
go build ./...
GOARCH=386 go test -v ./... || exit 1
GOARCH=amd64 go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1
- name: Contrib Build & Test
run: |
cd contrib
GOARCH=${{ matrix.goarch }}
for file in `find . -name go.mod`; do
dirpath=$(dirname $file)
# Ignore oracle database driver build&test.
if [ "oracle" = $(basename $dirpath) ]; then
continue 1
if ! go version|grep -q "1.17"; then
continue 1
fi
fi
cd $dirpath
go mod tidy
go build ./...
GOARCH=386 go test -v ./... || exit 1
GOARCH=amd64 go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1
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
- name: Main Build & Test
run: |
go build ./...
GOARCH=386 go test -v ./... || exit 1
GOARCH=amd64 go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1
- name: Stop containers
run: docker-compose -f ".github/workflows/docker-compose.yml" down
- name: Report Coverage
uses: codecov/codecov-action@v2
with:
flags: go-${{ matrix.go }}
flags: go-${{ matrix.go }}-${{ matrix.goarch }}

2
.gitignore vendored
View File

@ -15,3 +15,5 @@ cbuild
**/.DS_Store
.test/
cmd/gf/main
cmd/gf/gf
go.work

File diff suppressed because it is too large Load Diff

View File

@ -3,16 +3,18 @@ module github.com/gogf/gf/cmd/gf/v2
go 1.15
require (
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.0.6
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.0.6
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.0.6
github.com/gogf/gf/v2 v2.0.6
github.com/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
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/oracle/v2 => ../../contrib/drivers/oracle/
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,19 +14,24 @@ 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.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.4 h1:kHoYkfZP6+pe04aFTnhDH6GDROa5yJdHJVNxV3F46Tg=
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
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/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
@ -40,15 +48,20 @@ 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/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/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
@ -60,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=
@ -69,20 +81,27 @@ 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.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=
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=
@ -92,17 +111,22 @@ go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48
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=
@ -115,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=
@ -123,20 +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/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=
@ -164,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

@ -206,11 +206,14 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
}
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...")
@ -261,7 +264,7 @@ 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),
@ -287,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 {
@ -302,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

@ -88,14 +88,14 @@ 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 in.Shell != "" && gfile.Exists(in.Shell) {
if err = c.exeDockerShell(in.Shell); err != nil {
if err = c.exeDockerShell(ctx, in.Shell); err != nil {
return
}
}
@ -116,7 +116,7 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
}
for i, dockerTag := range dockerTags {
if i > 0 {
err = gproc.ShellRun(fmt.Sprintf(`docker tag %s %s`, dockerTagBase, dockerTag))
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker tag %s %s`, dockerTagBase, dockerTag))
if err != nil {
return
}
@ -130,7 +130,7 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
if in.Extra != "" {
dockerBuildOptions = fmt.Sprintf(`%s %s`, dockerBuildOptions, in.Extra)
}
err = gproc.ShellRun(fmt.Sprintf(`docker build -f %s . %s`, in.File, dockerBuildOptions))
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker build -f %s . %s`, in.File, dockerBuildOptions))
if err != nil {
return
}
@ -144,7 +144,7 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
if dockerTag == "" {
continue
}
err = gproc.ShellRun(fmt.Sprintf(`docker push %s`, dockerTag))
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker push %s`, dockerTag))
if err != nil {
return
}
@ -152,10 +152,10 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
return
}
func (c cDocker) exeDockerShell(shellFilePath string) error {
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(gfile.GetContents(shellFilePath))
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,809 +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/cmd/gf/v2/internal/cmd/gendao"
)
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`
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,
`cGenDaoBriefDaoPath`: cGenDaoBriefDaoPath,
`cGenDaoBriefDoPath`: cGenDaoBriefDoPath,
`cGenDaoBriefEntityPath`: cGenDaoBriefEntityPath,
`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:"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"`
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"`
}
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, in.DaoPath)
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(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, in.DoPath)
)
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, in.EntityPath)
)
// 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

@ -3,6 +3,8 @@ package cmd
import (
"context"
"fmt"
"go/parser"
"go/token"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
@ -15,18 +17,68 @@ import (
"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 generates 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`
cGenServiceBriefOverWrite = `overwrite service go files that already exist in generating folder. default: true`
)
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,
`cGenServiceBriefOverWrite`: cGenServiceBriefOverWrite,
})
}
type (
cGenService struct{}
cGenServiceInput struct {
g.Meta `name:"service" config:"gfcli.gen.service" brief:"parse struct and associated functions from packages to generate service go file"`
SrcFolder string `short:"s" name:"srcFolder" brief:"source folder path to be parsed. default: internal/logic" d:"internal/logic"`
DstFolder string `short:"d" name:"dstFolder" brief:"destination folder path storing automatically generated go files. default: internal/service" d:"internal/service"`
WatchFile string `short:"w" name:"watchFile" brief:"used in file watcher, it generates service go files only if given file is under srcFolder"`
StPattern string `short:"a" name:"stPattern" brief:"regular expression matching struct name for generating service. default: s([A-Z]\\w+)" d:"s([A-Z]\\w+)"`
Packages string `short:"p" name:"packages" brief:"produce go files only for given source packages, multiple packages joined with char ','"`
ImportPrefix string `short:"i" name:"importPrefix" brief:"custom import prefix to calculate import path for generated importing go file of logic"`
OverWrite bool `short:"o" name:"overwrite" brief:"overwrite service go files that already exist in generating folder. default: true" d:"true" orphan:"true"`
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}"`
OverWrite bool `short:"o" name:"overwrite" brief:"{cGenServiceBriefOverWrite}" d:"true" orphan:"true"`
}
cGenServiceOutput struct{}
)
@ -35,7 +87,7 @@ const (
genServiceFileLockSeconds = 10
)
func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServiceOutput, err error) {
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")
@ -65,7 +117,7 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
)
mlog.Debug("watchFileDir:", watchFileDir)
mlog.Debug("logicFolderDir:", srcFolderDir)
if !gstr.HasSuffix(srcFolderDir, in.SrcFolder) {
if !gstr.HasSuffix(gstr.Replace(srcFolderDir, `\`, `/`), in.SrcFolder) {
mlog.Printf(`ignore watch file "%s", not in source path "%s"`, in.WatchFile, in.SrcFolder)
return
}
@ -79,7 +131,7 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
`%s gen service -packages=%s`,
gfile.SelfName(), gfile.Basename(watchFileDir),
)
err = gproc.ShellRun(command)
err = gproc.ShellRun(ctx, command)
return
}
@ -101,13 +153,12 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
}
var (
isDirty bool
files []string
fileContent string
matches [][]string
importSrcPackages []string
inputPackages = gstr.SplitAndTrim(in.Packages, ",")
dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder))
isDirty bool
files []string
fileContent string
initImportSrcPackages []string
inputPackages = in.Packages
dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder))
)
srcFolders, err := gfile.ScanDir(in.SrcFolder, "*", false)
if err != nil {
@ -125,56 +176,25 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
}
var (
// StructName => FunctionDefinitions
srcPkgInterfaceMap = make(map[string]*garray.StrArray)
srcPkgInterfaceFuncArray *garray.StrArray
ok bool
srcPkgInterfaceMap = make(map[string]*garray.StrArray)
srcImportedPackages = garray.NewSortedStrArray().SetUnique(true)
ok bool
)
for _, file := range files {
fileContent = gfile.GetContents(file)
matches, err = gregex.MatchAllString(`func \((.+?)\) ([\s\S]+?) {`, fileContent)
// Calculate imported packages of source go files.
err = c.calculateImportedPackages(fileContent, srcImportedPackages)
if err != nil {
return nil, 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, "*")
// 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
}
if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil {
return nil, err
}
if len(structMatch) < 1 {
continue
}
structName = gstr.CaseCamel(structMatch[1])
if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok {
srcPkgInterfaceMap[structName] = garray.NewStrArray()
srcPkgInterfaceFuncArray = srcPkgInterfaceMap[structName]
}
// Remove package name calls of `dstPackageName` in produced codes.
functionHead, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, functionHead)
srcPkgInterfaceFuncArray.Append(functionHead)
// Calculate functions and interfaces for service generating.
err = c.calculateInterfaceFunctions(in, fileContent, srcPkgInterfaceMap, dstPackageName)
if err != nil {
return nil, err
}
}
importSrcPackages = append(
importSrcPackages,
initImportSrcPackages = append(
initImportSrcPackages,
fmt.Sprintf(`%s/%s`, in.ImportPrefix, gfile.Basename(srcFolder)),
)
// Ignore source packages if input packages given.
@ -186,7 +206,7 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
continue
}
// Generating go files for service.
if ok, err = c.generateServiceFiles(in, srcPkgInterfaceMap, dstPackageName); err != nil {
if ok, err = c.generateServiceFiles(in, srcPkgInterfaceMap, srcImportedPackages.Slice(), dstPackageName); err != nil {
return
}
if ok {
@ -196,17 +216,13 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
if isDirty {
// Generate initialization go file.
if len(importSrcPackages) > 0 {
if err = c.generateInitializationFile(in, importSrcPackages); err != nil {
if len(initImportSrcPackages) > 0 {
if err = c.generateInitializationFile(in, initImportSrcPackages); err != nil {
return
}
}
// Go imports updating.
mlog.Printf(`goimports go files in "%s", it may take seconds...`, in.DstFolder)
utils.GoImports(in.DstFolder)
// Replica v1 to v2 for GoFrame.
// Replace v1 to v2 for GoFrame.
if err = c.replaceGeneratedServiceContentGFV2(in); err != nil {
return nil, err
}
@ -218,13 +234,93 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
return
}
func (c cGen) generateServiceFiles(
in cGenServiceInput, srcPkgInterfaceMap map[string]*garray.StrArray, dstPackageName string,
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 {
// has alias and 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
)
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, "*")
// 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
}
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]
}
// Remove package name calls of `dstPackageName` in produced codes.
functionHead, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, functionHead)
srcPkgInterfaceFuncArray.Append(functionHead)
}
return nil
}
func (c cGenService) generateServiceFiles(
in cGenServiceInput,
srcPkgInterfaceMap map[string]*garray.StrArray,
srcImportedPackages []string,
dstPackageName string,
) (ok bool, err error) {
srcImportedPackagesContent := fmt.Sprintf(
"import (\n%s\n)", gstr.Join(srcImportedPackages, "\n"),
)
for structName, funcArray := range srcPkgInterfaceMap {
var (
filePath = gfile.Join(in.DstFolder, gstr.ToLower(structName)+".go")
filePath = gfile.Join(in.DstFolder, c.getDstFileNameCase(structName, in.DstFileNameCase)+".go")
generatedContent = gstr.ReplaceByMap(consts.TemplateGenServiceContent, g.MapStrStr{
"{Imports}": srcImportedPackagesContent,
"{StructName}": structName,
"{PackageName}": dstPackageName,
"{FuncDefinition}": funcArray.Join("\n\t"),
@ -250,7 +346,7 @@ func (c cGen) generateServiceFiles(
}
// isToGenerateServiceGoFile checks and returns whether the service content dirty.
func (c cGen) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrArray) bool {
func (c cGenService) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrArray) bool {
if !utils.IsFileDoNotEdit(filePath) {
mlog.Debugf(`ignore file as it is manually maintained: %s`, filePath)
return false
@ -280,7 +376,7 @@ func (c cGen) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrAr
return false
}
func (c cGen) generateInitializationFile(in cGenServiceInput, importSrcPackages []string) (err error) {
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")
@ -306,7 +402,7 @@ func (c cGen) generateInitializationFile(in cGenServiceInput, importSrcPackages
return nil
}
func (c cGen) replaceGeneratedServiceContentGFV2(in cGenServiceInput) (err error) {
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"`)
@ -316,3 +412,30 @@ func (c cGen) replaceGeneratedServiceContentGFV2(in cGenServiceInput) (err error
return content
}, in.DstFolder, "*.go", false)
}
// 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

@ -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,18 @@ func (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err
return
}
// Update the GoFrame version.
if in.Update {
mlog.Print("update goframe...")
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)
}
}
mlog.Print("initialization done! ")
if !in.Mono {
enjoyCommand := `gf run main.go`

View File

@ -13,7 +13,6 @@ import (
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gtimer"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
)
@ -47,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 (
@ -62,6 +62,7 @@ func init() {
`cRunFileBrief`: cRunFileBrief,
`cRunPathBrief`: cRunPathBrief,
`cRunExtraBrief`: cRunExtraBrief,
`cRunArgsBrief`: cRunArgsBrief,
})
}
@ -71,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{}
)
@ -85,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) {
@ -99,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)
@ -132,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
@ -150,11 +153,11 @@ func (app *cRunApp) Run() {
if runtime.GOOS == "windows" {
// Special handling for windows platform.
// DO NOT USE "cmd /c" command.
process = gproc.NewProcess(outputPath, gstr.SplitAndTrim(" ", app.Args))
process = gproc.NewProcess(runCommand, nil)
} else {
process = gproc.NewProcessCmd(outputPath, gstr.SplitAndTrim(" ", app.Args))
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,339 @@
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`
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,
`CGenDaoBriefDaoPath`: CGenDaoBriefDaoPath,
`CGenDaoBriefDoPath`: CGenDaoBriefDoPath,
`CGenDaoBriefEntityPath`: CGenDaoBriefEntityPath,
`CGenDaoBriefGJsonSupport`: CGenDaoBriefGJsonSupport,
`CGenDaoBriefImportPrefix`: CGenDaoBriefImportPrefix,
`CGenDaoBriefOverwriteDao`: CGenDaoBriefOverwriteDao,
`CGenDaoBriefModelFile`: CGenDaoBriefModelFile,
`CGenDaoBriefModelFileForDao`: CGenDaoBriefModelFileForDao,
`CGenDaoBriefDescriptionTag`: CGenDaoBriefDescriptionTag,
`CGenDaoBriefNoJsonTag`: CGenDaoBriefNoJsonTag,
`CGenDaoBriefNoModelComment`: CGenDaoBriefNoModelComment,
`CGenDaoBriefGroup`: CGenDaoBriefGroup,
`CGenDaoBriefJsonCase`: CGenDaoBriefJsonCase,
})
}
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"`
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"`
}
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.
}
)
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.
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,
})
}
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 tplDatetimeStr string
if in.WithTime {
tplDatetimeStr = fmt.Sprintf(`Created at %s`, createdAt.String())
}
return gstr.ReplaceByMap(origin, g.MapStrStr{
tplVarDatetimeStr: tplDatetimeStr,
})
}
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

@ -0,0 +1,186 @@
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"
)
// 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, in.DaoPath)
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(in, tableNameCamelCase, tableNameCamelLowerCase, importPrefix, dirPathDao, fileName)
// dao - internal
generateDaoInternal(in, tableNameCamelCase, tableNameCamelLowerCase, importPrefix, dirPathDao, fileName, fieldMap)
}
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 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
}
// 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,79 @@
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/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"
)
func generateDo(ctx context.Context, db gdb.DB, tableNames, newTableNames []string, in CGenDaoInternalInput) {
var (
doDirPath = gfile.Join(in.Path, in.DoPath)
)
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 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
}

View File

@ -0,0 +1,58 @@
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/database/gdb"
"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, db gdb.DB, tableNames, newTableNames []string, in CGenDaoInternalInput) {
var entityDirPath = gfile.Join(in.Path, in.EntityPath)
// 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 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
}

View File

@ -0,0 +1,205 @@
package gendao
import (
"bytes"
"fmt"
"strings"
"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
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"
}
// pgsql int32 slice.
case "_int2":
if gstr.ContainsI(field.Type, "unsigned") {
typeName = "[]uint"
} else {
typeName = "[]int"
}
// pgsql int64 slice.
case "_int4", "_int8":
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
}
// 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

@ -40,6 +40,7 @@ package internal
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
)

View File

@ -7,6 +7,8 @@ const TemplateGenServiceContent = `
package {PackageName}
{Imports}
type I{StructName} interface {
{FuncDefinition}
}

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,41 +1,37 @@
package utils
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/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gstr"
"golang.org/x/tools/imports"
)
var (
gofmtPath = gproc.SearchBinaryPath("gofmt") // gofmtPath is the binary path of command `gofmt`.
goimportsPath = gproc.SearchBinaryPath("goimports") // gofmtPath is the binary path of command `goimports`.
)
// 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 == "" {
mlog.Fatal(`command "gofmt" not found`)
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 command = fmt.Sprintf(`%s -w %s`, gofmtPath, path)
result, err := gproc.ShellExec(command)
if err != nil {
mlog.Fatalf(`error executing command "%s": %s`, command, result)
}
}
// GoImports formats the source file using command `goimports -w PATH`.
func GoImports(path string) {
if goimportsPath == "" {
mlog.Fatal(`command "goimports" not found`)
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)
}
var command = fmt.Sprintf(`%s -w %s`, goimportsPath, path)
result, err := gproc.ShellExec(command)
if err != nil {
mlog.Fatalf(`error executing command "%s": %s`, command, result)
mlog.Printf(`error format "%s" go files: %v`, path, err)
}
}

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,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"
@ -485,3 +486,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

@ -499,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)
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,7 @@ package gtype
import (
"sync/atomic"
"github.com/gogf/gf/v2/internal/deepcopy"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/util/gconv"
)
@ -71,3 +72,11 @@ func (v *Interface) UnmarshalValue(value interface{}) error {
v.Set(value)
return nil
}
// DeepCopy implements interface for deep copy of current type.
func (v *Interface) DeepCopy() interface{} {
if v == nil {
return nil
}
return NewInterface(deepcopy.Copy(v.Val()))
}

View File

@ -8,8 +8,9 @@ package gtype
import (
"bytes"
"github.com/gogf/gf/v2/util/gconv"
"sync/atomic"
"github.com/gogf/gf/v2/util/gconv"
)
// String is a struct for concurrent-safe operation for type string.
@ -69,3 +70,11 @@ func (v *String) UnmarshalValue(value interface{}) error {
v.Set(gconv.String(value))
return nil
}
// DeepCopy implements interface for deep copy of current type.
func (v *String) DeepCopy() interface{} {
if v == nil {
return nil
}
return NewString(v.Val())
}

View File

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

View File

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

View File

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

View File

@ -27,7 +27,19 @@ func Test_Bool(t *testing.T) {
t.AssertEQ(iClone1.Set(true), false)
t.AssertEQ(iClone1.Val(), true)
// 空参测试
t.AssertEQ(iClone1.Cas(false, true), false)
t.AssertEQ(iClone1.String(), "true")
t.AssertEQ(iClone1.Cas(true, false), true)
t.AssertEQ(iClone1.String(), "false")
copyVal := i1.DeepCopy()
iClone.Set(true)
t.AssertNE(copyVal, iClone.Val())
iClone = nil
copyVal = iClone.DeepCopy()
t.AssertNil(copyVal)
// empty param test
i2 := gtype.NewBool()
t.AssertEQ(i2.Val(), false)
})

View File

@ -34,9 +34,21 @@ func Test_Byte(t *testing.T) {
wg.Wait()
t.AssertEQ(byte(addTimes), i.Val())
// 空参测试
// empty param test
i1 := gtype.NewByte()
t.AssertEQ(i1.Val(), byte(0))
i2 := gtype.NewByte(byte(64))
t.AssertEQ(i2.String(), "64")
t.AssertEQ(i2.Cas(byte(63), byte(65)), false)
t.AssertEQ(i2.Cas(byte(64), byte(65)), true)
copyVal := i2.DeepCopy()
i2.Set(byte(65))
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

View File

@ -22,9 +22,19 @@ func Test_Bytes(t *testing.T) {
t.AssertEQ(iClone.Set([]byte("123")), []byte("abc"))
t.AssertEQ(iClone.Val(), []byte("123"))
// 空参测试
// empty param test
i1 := gtype.NewBytes()
t.AssertEQ(i1.Val(), nil)
i2 := gtype.NewBytes([]byte("abc"))
t.Assert(i2.String(), "abc")
copyVal := i2.DeepCopy()
i2.Set([]byte("def"))
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

View File

@ -23,9 +23,22 @@ func Test_Float32(t *testing.T) {
t.AssertEQ(iClone.Set(0.1), float32(0))
t.AssertEQ(iClone.Val(), float32(0.1))
// 空参测试
// empty param test
i1 := gtype.NewFloat32()
t.AssertEQ(i1.Val(), float32(0))
i2 := gtype.NewFloat32(1.23)
t.AssertEQ(i2.Add(3.21), float32(4.44))
t.AssertEQ(i2.Cas(4.45, 5.55), false)
t.AssertEQ(i2.Cas(4.44, 5.55), true)
t.AssertEQ(i2.String(), "5.55")
copyVal := i2.DeepCopy()
i2.Set(float32(6.66))
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

View File

@ -22,9 +22,22 @@ func Test_Float64(t *testing.T) {
iClone := i.Clone()
t.AssertEQ(iClone.Set(0.1), float64(0))
t.AssertEQ(iClone.Val(), float64(0.1))
// 空参测试
// empty param test
i1 := gtype.NewFloat64()
t.AssertEQ(i1.Val(), float64(0))
i2 := gtype.NewFloat64(1.1)
t.AssertEQ(i2.Add(3.3), 4.4)
t.AssertEQ(i2.Cas(4.5, 5.5), false)
t.AssertEQ(i2.Cas(4.4, 5.5), true)
t.AssertEQ(i2.String(), "5.5")
copyVal := i2.DeepCopy()
i2.Set(6.6)
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

View File

@ -35,9 +35,22 @@ func Test_Int32(t *testing.T) {
wg.Wait()
t.AssertEQ(int32(addTimes), i.Val())
// 空参测试
// empty param test
i1 := gtype.NewInt32()
t.AssertEQ(i1.Val(), int32(0))
i2 := gtype.NewInt32(11)
t.AssertEQ(i2.Add(1), int32(12))
t.AssertEQ(i2.Cas(11, 13), false)
t.AssertEQ(i2.Cas(12, 13), true)
t.AssertEQ(i2.String(), "13")
copyVal := i2.DeepCopy()
i2.Set(14)
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

View File

@ -35,9 +35,22 @@ func Test_Int64(t *testing.T) {
wg.Wait()
t.AssertEQ(int64(addTimes), i.Val())
// 空参测试
// empty param test
i1 := gtype.NewInt64()
t.AssertEQ(i1.Val(), int64(0))
i2 := gtype.NewInt64(11)
t.AssertEQ(i2.Add(1), int64(12))
t.AssertEQ(i2.Cas(11, 13), false)
t.AssertEQ(i2.Cas(12, 13), true)
t.AssertEQ(i2.String(), "13")
copyVal := i2.DeepCopy()
i2.Set(14)
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

View File

@ -34,9 +34,22 @@ func Test_Int(t *testing.T) {
wg.Wait()
t.AssertEQ(addTimes, i.Val())
// 空参测试
// empty param test
i1 := gtype.NewInt()
t.AssertEQ(i1.Val(), 0)
i2 := gtype.NewInt(11)
t.AssertEQ(i2.Add(1), 12)
t.AssertEQ(i2.Cas(11, 13), false)
t.AssertEQ(i2.Cas(12, 13), true)
t.AssertEQ(i2.String(), "13")
copyVal := i2.DeepCopy()
i2.Set(14)
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

View File

@ -24,9 +24,18 @@ func Test_Interface(t *testing.T) {
t.AssertEQ(iClone.Set(t2), t1)
t.AssertEQ(iClone.Val().(Temp), t2)
// 空参测试
// empty param test
i1 := gtype.New()
t.AssertEQ(i1.Val(), nil)
i2 := gtype.New("gf")
t.AssertEQ(i2.String(), "gf")
copyVal := i2.DeepCopy()
i2.Set("goframe")
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

View File

@ -21,8 +21,15 @@ func Test_String(t *testing.T) {
iClone := i.Clone()
t.AssertEQ(iClone.Set("123"), "abc")
t.AssertEQ(iClone.Val(), "123")
// 空参测试
t.AssertEQ(iClone.String(), "123")
//
copyVal := iClone.DeepCopy()
iClone.Set("124")
t.AssertNE(copyVal, iClone.Val())
iClone = nil
copyVal = iClone.DeepCopy()
t.AssertNil(copyVal)
// empty param test
i1 := gtype.NewString()
t.AssertEQ(i1.Val(), "")
})

View File

@ -35,9 +35,22 @@ func Test_Uint32(t *testing.T) {
wg.Wait()
t.AssertEQ(uint32(addTimes), i.Val())
// 空参测试
// empty param test
i1 := gtype.NewUint32()
t.AssertEQ(i1.Val(), uint32(0))
i2 := gtype.NewUint32(11)
t.AssertEQ(i2.Add(1), uint32(12))
t.AssertEQ(i2.Cas(11, 13), false)
t.AssertEQ(i2.Cas(12, 13), true)
t.AssertEQ(i2.String(), "13")
copyVal := i2.DeepCopy()
i2.Set(14)
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

View File

@ -40,9 +40,22 @@ func Test_Uint64(t *testing.T) {
wg.Wait()
t.AssertEQ(uint64(addTimes), i.Val())
// 空参测试
// empty param test
i1 := gtype.NewUint64()
t.AssertEQ(i1.Val(), uint64(0))
i2 := gtype.NewUint64(11)
t.AssertEQ(i2.Add(1), uint64(12))
t.AssertEQ(i2.Cas(11, 13), false)
t.AssertEQ(i2.Cas(12, 13), true)
t.AssertEQ(i2.String(), "13")
copyVal := i2.DeepCopy()
i2.Set(14)
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}
func Test_Uint64_JSON(t *testing.T) {

View File

@ -34,9 +34,22 @@ func Test_Uint(t *testing.T) {
wg.Wait()
t.AssertEQ(uint(addTimes), i.Val())
// 空参测试
// empty param test
i1 := gtype.NewUint()
t.AssertEQ(i1.Val(), uint(0))
i2 := gtype.NewUint(11)
t.AssertEQ(i2.Add(1), uint(12))
t.AssertEQ(i2.Cas(11, 13), false)
t.AssertEQ(i2.Cas(12, 13), true)
t.AssertEQ(i2.String(), "13")
copyVal := i2.DeepCopy()
i2.Set(14)
t.AssertNE(copyVal, iClone.Val())
i2 = nil
copyVal = i2.DeepCopy()
t.AssertNil(copyVal)
})
}

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