Compare commits

..

10 Commits

111 changed files with 1683 additions and 938 deletions

View File

@ -1,16 +1,16 @@
**Please ensure you adhere to every item in this list.**
+ The PR title is formatted as follows: `<type>[optional scope]: <description>` For example, `fix(os/gtime): fix time zone issue`
+ `<type>` is mandatory and can be one of `fix`, `feat`, `build`, `ci`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`
+ fix: Used when a bug has been fixed.
+ feat: Used when a new feature has been added.
+ build: Used for modifications to the project build system, such as changes to dependencies, external interfaces, or upgrading Node version.
+ ci: Used for modifications to continuous integration processes, such as changes to Travis, Jenkins workflow configurations.
+ docs: Used for modifications to documentation, such as changes to README files, API documentation, etc.
+ style: Used for changes to code style, such as adjustments to indentation, spaces, blank lines, etc.
+ refactor: Used for code refactoring, such as changes to code structure, variable names, function names, without altering functionality.
+ perf: Used for performance optimization, such as improving code performance, reducing memory usage, etc.
+ test: Used for modifications to test cases, such as adding, deleting, or modifying test cases for code.
+ chore: Used for modifications to non-business-related code, such as changes to build processes or tool configurations.
+ `fix`: Used when a bug has been fixed.
+ `feat`: Used when a new feature has been added.
+ `build`: Used for modifications to the project build system, such as changes to dependencies, external interfaces, or upgrading Node version.
+ `ci`: Used for modifications to continuous integration processes, such as changes to Travis, Jenkins workflow configurations.
+ `docs`: Used for modifications to documentation, such as changes to README files, API documentation, etc.
+ `style`: Used for changes to code style, such as adjustments to indentation, spaces, blank lines, etc.
+ `refactor`: Used for code refactoring, such as changes to code structure, variable names, function names, without altering functionality.
+ `perf`: Used for performance optimization, such as improving code performance, reducing memory usage, etc.
+ `test`: Used for modifications to test cases, such as adding, deleting, or modifying test cases for code.
+ `chore`: Used for modifications to non-business-related code, such as changes to build processes or tool configurations.
+ After `<type>`, specify the affected package name or scope in parentheses, for example, `(os/gtime)`.
+ The part after the colon uses the verb tense + phrase that completes the blank in
+ Lowercase verb after the colon

View File

@ -239,15 +239,15 @@ jobs:
export PATH="$PATH:$(go env GOPATH)/bin"
- name: Before Script
run: bash .github/workflows/before_script.sh
run: bash .github/workflows/scripts/before_script.sh
- name: Build & Test
if: ${{ (github.event_name == 'push' && github.ref != 'refs/heads/master') || github.event_name == 'pull_request' }}
run: bash .github/workflows/ci-main.sh
run: bash .github/workflows/scripts/ci-main.sh
- name: Build & Test & Coverage
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
run: bash .github/workflows/ci-main.sh coverage
run: bash .github/workflows/scripts/ci-main.sh coverage
- name: Stop Redis Cluster Containers
run: docker compose -f ".github/workflows/redis/docker-compose.yml" down

View File

@ -64,9 +64,9 @@ jobs:
cache-dependency-path: '**/go.sum'
- name: Before Script
run: bash .github/workflows/before_script.sh
run: bash .github/workflows/scripts/before_script.sh
- name: Build & Test
run: bash .github/workflows/ci-sub.sh
run: bash .github/workflows/scripts/ci-sub.sh

View File

@ -1,38 +0,0 @@
name: Deploy to GitHub Pages
on:
push:
branches:
- 'doc-build'
schedule:
- cron: '0 15 * * *'
jobs:
deploy:
name: Deploy to GitHub Pages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: doc-build
- uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
- name: Set Up Golang Environment
uses: actions/setup-go@v5
with:
go-version: 1.23.4
cache: false
- name: download goframe docs
run: ./download.sh
- name: Install dependencies
run: npm ci
- name: Build website
run: npm run build
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build
cname: pages.goframe.org

View File

@ -3,7 +3,10 @@
coverage=$1
# update code of submodules
make subup
git clone https://github.com/gogf/examples
# update go.mod in examples directory to replace github.com/gogf/gf packages with local directory
bash .github/workflows/scripts/replace_examples_gomod.sh
# find all path that contains go.mod.
for file in `find . -name go.mod`; do
@ -22,14 +25,14 @@ for file in `find . -name go.mod`; do
fi
# Check if it's a contrib directory or examples directory
if [[ $dirpath =~ "/contrib/" ]] || [ "examples" = $(basename $dirpath) ]; then
if [[ $dirpath =~ "/contrib/" ]] || [[ $dirpath =~ "/examples/" ]]; then
# Check if go version meets the requirement
if ! go version | grep -qE "go${LATEST_GO_VERSION}"; then
echo "ignore path $dirpath as go version is not ${LATEST_GO_VERSION}: $(go version)"
continue 1
fi
# If it's examples directory, only build without tests
if [ "examples" = $(basename $dirpath) ]; then
if [[ $dirpath =~ "/examples/" ]]; then
echo "the examples directory only needs to be built, not unit tests and coverage tests."
cd $dirpath
go mod tidy

View File

@ -0,0 +1,81 @@
#!/usr/bin/env bash
# Get the absolute path to the repository root
repo_root=$(pwd)
workdir=$repo_root/examples
echo "Prepare to process go.mod files in the ${workdir} directory"
# Check if examples directory exists
if [ ! -d "${workdir}" ]; then
echo "Error: examples directory not found at ${workdir}"
exit 1
fi
# Check if find command is available
if ! command -v find &> /dev/null; then
echo "Error: find command not found!"
exit 1
fi
for file in `find ${workdir} -name go.mod`; do
goModPath=$(dirname $file)
echo ""
echo "Processing dir: $goModPath"
# Calculate relative path to root
# First get the relative path from go.mod to repo root
relativePath=""
current="$goModPath"
while [ "$current" != "$repo_root" ]; do
relativePath="../$relativePath"
current=$(dirname "$current")
done
relativePath=${relativePath%/} # Remove trailing slash
echo "Relative path to root: $relativePath"
# Get all github.com/gogf/gf dependencies
# Use awk to get package names without version numbers
dependencies=$(awk '/^[[:space:]]*github\.com\/gogf\/gf\// {print $1}' "$file" | sort -u)
if [ -n "$dependencies" ]; then
echo "Found GoFrame dependencies:"
echo "$dependencies"
echo "Adding replace directives..."
# Create temporary file
temp_file="${file}.tmp"
# Remove existing replace directives and copy to temp file
sed '/^replace.*github\.com\/gogf\/gf.*/d' "$file" > "$temp_file"
# Add new replace block
echo "" >> "$temp_file"
echo "replace (" >> "$temp_file"
while IFS= read -r dep; do
# Skip empty lines
[ -z "$dep" ] && continue
# Calculate the relative path for the replacement
if [[ "$dep" == "github.com/gogf/gf/v2" ]]; then
replacement="$relativePath"
else
# Extract the path after v2 and remove trailing version
subpath=$(echo "$dep" | sed -E 's/github\.com\/gogf\/gf\/(contrib\/[^/]+\/[^/]+)\/v2.*/\1/')
replacement="$relativePath/$subpath"
fi
echo " $dep => $replacement/" >> "$temp_file"
done <<< "$dependencies"
echo ")" >> "$temp_file"
# Replace original file with temporary file
mv "$temp_file" "$file"
echo "Replace directives added to $file"
else
echo "No GoFrame dependencies found in $file"
fi
done
echo "\nAll go.mod files have been processed successfully."

33
.make_tidy.sh Executable file
View File

@ -0,0 +1,33 @@
#!/usr/bin/env bash
workdir=.
echo "Prepare to tidy all go.mod files in the ${workdir} directory"
# check find command support or not
output=$(find "${workdir}" -name go.mod 2>&1)
if [[ $? -ne 0 ]]; then
echo "Error: please use bash or zsh to run!"
exit 1
fi
for file in `find ${workdir} -name go.mod`; do
goModPath=$(dirname $file)
echo ""
echo "processing dir: $goModPath"
if [[ $goModPath =~ "/testdata/" ]]; then
echo "ignore testdata path $goModPath"
continue 1
fi
if [[ $goModPath =~ "/examples/" ]]; then
echo "ignore examples path $goModPath"
continue 1
fi
cd $goModPath
go mod tidy
# Remove toolchain line if exists
sed -i '' '/^toolchain/d' go.mod
cd - > /dev/null
done

View File

@ -17,7 +17,7 @@ fi
workdir=.
newVersion=$2
echo "Prepare to replace the GF library version numbers in all go.mod files in the ${workdir} directory with ${newVersion}"
echo "Prepare to replace the GoFrame library version numbers in all go.mod files in the ${workdir} directory with ${newVersion}"
# check find command support or not
output=$(find "${workdir}" -name go.mod 2>&1)
@ -49,6 +49,11 @@ for file in `find ${workdir} -name go.mod`; do
continue 1
fi
if [[ $goModPath =~ "/examples/" ]]; then
echo "ignore examples path $goModPath"
continue 1
fi
cd $goModPath
if [ $goModPath = "./cmd/gf" ]; then
mv go.work go.work.version.bak
@ -59,15 +64,18 @@ for file in `find ${workdir} -name go.mod`; do
go mod edit -replace github.com/gogf/gf/contrib/drivers/oracle/v2=../../contrib/drivers/oracle
go mod edit -replace github.com/gogf/gf/contrib/drivers/pgsql/v2=../../contrib/drivers/pgsql
go mod edit -replace github.com/gogf/gf/contrib/drivers/sqlite/v2=../../contrib/drivers/sqlite
# else
# cd -
# continue 1
fi
go mod tidy
# Upgrading only GF related libraries, sometimes even if a version number is specified, it may not be possible to successfully upgrade. Please confirm before submitting the code
# Remove toolchain line if exists
sed -i '' '/^toolchain/d' go.mod
# Upgrading only GoFrame related libraries, sometimes even if a version number is specified,
# it may not be possible to successfully upgrade. Please confirm before submitting the code
go list -f "{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}" -m all | grep "^github.com/gogf/gf"
go list -f "{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}" -m all | grep "^github.com/gogf/gf" | xargs -L1 go get -v
go mod tidy
# Remove toolchain line if exists
sed -i '' '/^toolchain/d' go.mod
if [ $goModPath = "./cmd/gf" ]; then
go mod edit -dropreplace github.com/gogf/gf/v2
go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/clickhouse/v2

View File

@ -3,17 +3,7 @@ SHELL := /bin/bash
# execute "go mod tidy" on all folders that have go.mod file
.PHONY: tidy
tidy:
$(eval files=$(shell find . -name go.mod))
@set -e; \
for file in ${files}; do \
goModPath=$$(dirname $$file); \
if ! echo $$goModPath | grep -q "testdata"; then \
echo "handle: $$goModPath"; \
cd $$goModPath; \
go mod tidy; \
cd -; \
fi \
done
./.make_tidy.sh
# execute "golangci-lint" to check code style
.PHONY: lint
@ -25,7 +15,7 @@ lint:
version:
@set -e; \
newVersion=$(to); \
./.set_version.sh ./ $$newVersion; \
./.make_version.sh ./ $$newVersion; \
echo "make version to=$(to) done"
@ -33,10 +23,9 @@ version:
.PHONY: subup
subup:
@set -e; \
cd examples; \
echo "Updating submodules..."; \
git pull origin; \
cd ..;
git submodule init;\
git submodule update;
# update and commit submodules
.PHONY: subsync

View File

@ -36,7 +36,7 @@ A powerful framework for faster, easier, and more efficient project development.
💖 [Thanks to all the contributors who made GoFrame possible](https://github.com/gogf/gf/graphs/contributors) 💖
<a href="https://github.com/gogf/gf/graphs/contributors">
<img src="https://goframe.org/img/contributors.svg?version=v2.8.3" alt="goframe contributors"/>
<img src="https://goframe.org/img/contributors.svg?version=v2.9.0-beta" alt="goframe contributors"/>
</a>
# License

View File

@ -1,15 +1,15 @@
module github.com/gogf/gf/cmd/gf/v2
go 1.20
go 1.22
require (
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.8.3
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.8.3
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.3
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.8.3
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.3
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.8.3
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.9.0-beta
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.9.0-beta
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.0-beta
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.9.0-beta
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.9.0-beta
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.9.0-beta
github.com/gogf/gf/v2 v2.9.0-beta
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f
github.com/olekukonko/tablewriter v0.0.5
github.com/schollz/progressbar/v3 v3.15.0
@ -48,10 +48,10 @@ require (
github.com/rivo/uniseg v0.4.7 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sijms/go-ora/v2 v2.7.10 // indirect
go.opentelemetry.io/otel v1.24.0 // indirect
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/sdk v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.opentelemetry.io/otel v1.32.0 // indirect
go.opentelemetry.io/otel/metric v1.32.0 // indirect
go.opentelemetry.io/otel/sdk v1.32.0 // indirect
go.opentelemetry.io/otel/trace v1.32.0 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sync v0.10.0 // indirect

View File

@ -1,11 +1,17 @@
aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
@ -40,24 +46,11 @@ github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiU
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.8.3 h1:b/AQMTxiHKPHsidEdk471AC5pkfoK88a5cPmKnzE53U=
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.8.3/go.mod h1:qYrF+x5urXLhce3pMcUAyccIsw3Oec0htynoDE4Boi4=
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.8.3 h1:F7Gt1y6YsYOIvgrUlRK07H29BL77dEgLPXilTqqVC80=
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.8.3/go.mod h1:K5prIMZwHANSZrqZbfm6PoEIMfLtd0PwR7u+hZD9HFs=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.3 h1:RtoBg5HWACFrgIrFkpzH94kxSd5EWefNAq5k6olNY6c=
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.8.3/go.mod h1:elZjckHRCejwml5Kdx2zfhOUDiAV3r5i4BgXcKAeH00=
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.8.3 h1:10/RCoWmvQ6PSm+leoS6CsKijH4dB38HOXLgP5+aScQ=
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.8.3/go.mod h1:XSaHf3/vTlzj/zioUbzKmaffPuoKvPV639fT91caheM=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.3 h1:DvpoiVac1cwGVDTqC6wzFbDb+gXNzcceRgZUIcuTmaI=
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.8.3/go.mod h1:zugvYVb6c/X9rJ8Gb6b5WkMe+bFz2BsxQ5OLf4RSZos=
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.8.3 h1:3pdibfm4UOiTGGh6UD8jfMyGZBGH9ikrrIMU8i/XANA=
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.8.3/go.mod h1:G5rfcFkBhtmZT4+CU7A3fJH3sNmP4WRIaJ+4JFeVE08=
github.com/gogf/gf/v2 v2.8.3 h1:h9Px3lqJnnH6It0AqHRz4/1hx0JmvaSf1IvUir5x1rA=
github.com/gogf/gf/v2 v2.8.3/go.mod h1:n++xPYGUUMadw6IygLEgGZqc6y6DRLrJKg5kqCrPLWY=
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f h1:7xfXR/BhG3JDqO1s45n65Oyx9t4E/UqDOXep6jXdLCM=
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f/go.mod h1:HnYoio6S7VaFJdryKcD/r9HgX+4QzYfr00XiXUo/xz0=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
@ -66,7 +59,9 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
@ -80,7 +75,12 @@ github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhB
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
@ -109,6 +109,7 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
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/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
@ -117,6 +118,8 @@ github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qq
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/schollz/progressbar/v3 v3.15.0 h1:cNZmcNiVyea6oofBTg80ZhVXxf3wG/JoAhqCCwopkQo=
github.com/schollz/progressbar/v3 v3.15.0/go.mod h1:ncBdc++eweU0dQoeZJ3loXoAc+bjaallHRIm8pVVeQM=
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
@ -131,22 +134,23 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
go.opentelemetry.io/otel v1.24.0 h1:0LAOdjNmQeSTzGBzduGe/rU4tZhMwL5rWgtp9Ku5Jfo=
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
go.opentelemetry.io/otel/metric v1.24.0 h1:6EhoGWWK28x1fbpA4tYTOWBkPefTDQnb8WSGXlc88kI=
go.opentelemetry.io/otel/metric v1.24.0/go.mod h1:VYhLe1rFfxuTXLgj4CBiyz+9WYBA8pNGJgDcSFRKBco=
go.opentelemetry.io/otel/sdk v1.24.0 h1:YMPPDNymmQN3ZgczicBY3B6sf9n62Dlj9pWD3ucgoDw=
go.opentelemetry.io/otel/sdk v1.24.0/go.mod h1:KVrIYw6tEubO9E96HQpcmpTKDVn9gdv35HoYiQWGDFg=
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M=
go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8=
go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4=
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
go.opentelemetry.io/otel/trace v1.24.0 h1:CsKnnL4dUAr/0llH9FKuc698G04IrpWV0MQA/Y1YELI=
go.opentelemetry.io/otel/trace v1.24.0/go.mod h1:HPc3Xr/cOApsBI154IU0OI0HJexz+aw5uPdbs3UCjNU=
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
@ -202,8 +206,9 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@ -1,4 +1,4 @@
go 1.20
go 1.22
use (
./

View File

@ -36,7 +36,7 @@ type (
Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
ShardingPattern []string `name:"ShardingPattern" short:"sp" brief:"{CGenDaoBriefShardingPattern}"`
ShardingPattern []string `name:"shardingPattern" short:"sp" brief:"{CGenDaoBriefShardingPattern}"`
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}"`

View File

@ -12,7 +12,7 @@ import (
)
// Val returns the current value of `v`.
func (v *Var) Val() interface{} {
func (v *Var) Val() any {
if v == nil {
return nil
}
@ -25,7 +25,7 @@ func (v *Var) Val() interface{} {
}
// Interface is alias of Val.
func (v *Var) Interface() interface{} {
func (v *Var) Interface() any {
return v.Val()
}

View File

@ -2,11 +2,9 @@ module github.com/gogf/gf/contrib/config/apollo/v2
go 1.22
toolchain go1.22.0
require (
github.com/apolloconfig/agollo/v4 v4.3.1
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
)
require (

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/config/consul/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/hashicorp/consul/api v1.24.0
github.com/hashicorp/go-cleanhttp v0.5.2
)

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/config/kubecm/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
k8s.io/api v0.27.4
k8s.io/apimachinery v0.27.4
k8s.io/client-go v0.27.4

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/config/nacos/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/nacos-group/nacos-sdk-go/v2 v2.2.5
)

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/config/polaris/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/polarismesh/polaris-go v1.5.8
)

View File

@ -2,11 +2,9 @@ module github.com/gogf/gf/contrib/drivers/clickhouse/v2
go 1.22
toolchain go1.22.0
require (
github.com/ClickHouse/clickhouse-go/v2 v2.0.15
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/google/uuid v1.6.0
github.com/shopspring/decimal v1.3.1
)

View File

@ -2,13 +2,11 @@ module github.com/gogf/gf/contrib/drivers/dm/v2
go 1.22
toolchain go1.22.0
replace github.com/gogf/gf/v2 => ../../../
require (
gitee.com/chunanyong/dm v1.8.12
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
)
require (

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/drivers/mssql/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/microsoft/go-mssqldb v1.7.1
)

View File

@ -2,11 +2,9 @@ module github.com/gogf/gf/contrib/drivers/mysql/v2
go 1.22
toolchain go1.22.0
require (
github.com/go-sql-driver/mysql v1.7.1
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
)
require (

View File

@ -1741,7 +1741,7 @@ func Test_Issue4086(t *testing.T) {
},
})
})
return
gtest.C(t, func(t *gtest.T) {
type ProxyParam struct {
ProxyId int64 `json:"proxyId" orm:"proxy_id"`

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/drivers/oracle/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/sijms/go-ora/v2 v2.7.10
)

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/drivers/pgsql/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/lib/pq v1.10.9
)

View File

@ -2,11 +2,9 @@ module github.com/gogf/gf/contrib/drivers/sqlite/v2
go 1.22
toolchain go1.22.0
require (
github.com/glebarez/go-sqlite v1.21.2
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
)
require (

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/drivers/sqlitecgo/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/mattn/go-sqlite3 v1.14.17
)

View File

@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/metric/otelmetric/v2
go 1.22
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/prometheus/client_golang v1.19.1
go.opentelemetry.io/contrib/instrumentation/runtime v0.49.0
go.opentelemetry.io/otel v1.32.0

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/nosql/redis/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/redis/go-redis/v9 v9.7.0
go.opentelemetry.io/otel v1.32.0
go.opentelemetry.io/otel/trace v1.32.0

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/registry/consul/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/hashicorp/consul/api v1.26.1
)

View File

@ -3,7 +3,7 @@ module github.com/gogf/gf/contrib/registry/etcd/v2
go 1.22
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
go.etcd.io/etcd/client/v3 v3.5.17
google.golang.org/grpc v1.59.0
)

View File

@ -45,6 +45,7 @@ func Test_HTTP_Registry(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetDiscovery(gsvc.GetRegistry())
client.SetPrefix(fmt.Sprintf("http://%s", svcName))
// GET
t.Assert(client.GetContent(ctx, "/http-registry"), svcName)
@ -71,6 +72,7 @@ func Test_HTTP_Discovery_Disable(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetDiscovery(gsvc.GetRegistry())
client.SetPrefix(fmt.Sprintf("http://%s", svcName))
result, err := client.Get(ctx, "/http-registry")
defer result.Close()

View File

@ -2,9 +2,7 @@ module github.com/gogf/gf/contrib/registry/file/v2
go 1.22
toolchain go1.22.0
require github.com/gogf/gf/v2 v2.8.3
require github.com/gogf/gf/v2 v2.9.0-beta
require (
github.com/BurntSushi/toml v1.4.0 // indirect

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/registry/nacos/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/nacos-group/nacos-sdk-go/v2 v2.2.7
)

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/registry/polaris/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
github.com/polarismesh/polaris-go v1.5.8
)

View File

@ -2,11 +2,9 @@ module github.com/gogf/gf/contrib/registry/zookeeper/v2
go 1.22
toolchain go1.22.0
require (
github.com/go-zookeeper/zk v1.0.3
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
golang.org/x/sync v0.10.0
)

View File

@ -2,11 +2,9 @@ module github.com/gogf/gf/contrib/rpc/grpcx/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/contrib/registry/file/v2 v2.8.3
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/contrib/registry/file/v2 v2.9.0-beta
github.com/gogf/gf/v2 v2.9.0-beta
go.opentelemetry.io/otel v1.32.0
go.opentelemetry.io/otel/trace v1.32.0
google.golang.org/grpc v1.64.1

View File

@ -2,9 +2,7 @@ module github.com/gogf/gf/contrib/sdk/httpclient/v2
go 1.22
toolchain go1.22.0
require github.com/gogf/gf/v2 v2.8.3
require github.com/gogf/gf/v2 v2.9.0-beta
require (
github.com/BurntSushi/toml v1.4.0 // indirect

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/trace/otlpgrpc/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
go.opentelemetry.io/otel v1.32.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.24.0

View File

@ -2,10 +2,8 @@ module github.com/gogf/gf/contrib/trace/otlphttp/v2
go 1.22
toolchain go1.22.0
require (
github.com/gogf/gf/v2 v2.8.3
github.com/gogf/gf/v2 v2.9.0-beta
go.opentelemetry.io/otel v1.32.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.24.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.24.0

View File

@ -0,0 +1,82 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gdb
import (
"reflect"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/util/gconv"
)
// iVal is used for type assert api for Val().
type iVal interface {
Val() any
}
var (
// converter is the internal type converter for gdb.
converter = gconv.NewConverter()
)
func init() {
converter.RegisterAnyConverterFunc(
sliceTypeConverterFunc,
reflect.TypeOf([]string{}),
reflect.TypeOf([]float32{}),
reflect.TypeOf([]float64{}),
reflect.TypeOf([]int{}),
reflect.TypeOf([]int32{}),
reflect.TypeOf([]int64{}),
reflect.TypeOf([]uint{}),
reflect.TypeOf([]uint32{}),
reflect.TypeOf([]uint64{}),
)
}
// GetConverter returns the internal type converter for gdb.
func GetConverter() gconv.Converter {
return converter
}
func sliceTypeConverterFunc(from any, to reflect.Value) (err error) {
v, ok := from.(iVal)
if !ok {
return nil
}
fromVal := v.Val()
switch x := fromVal.(type) {
case []byte:
dst := to.Addr().Interface()
err = json.Unmarshal(x, dst)
case string:
dst := to.Addr().Interface()
err = json.Unmarshal([]byte(x), dst)
default:
fromType := reflect.TypeOf(fromVal)
switch fromType.Kind() {
case reflect.Slice:
convertOption := gconv.ConvertOption{
SliceOption: gconv.SliceOption{ContinueOnError: true},
MapOption: gconv.MapOption{ContinueOnError: true},
StructOption: gconv.StructOption{ContinueOnError: true},
}
dv, err := converter.ConvertWithTypeName(fromVal, to.Type().String(), convertOption)
if err != nil {
return err
}
to.Set(reflect.ValueOf(dv))
default:
err = gerror.Newf(
`unsupported type converting from type "%T" to type "%T"`,
fromVal, to,
)
}
}
return err
}

View File

@ -225,7 +225,6 @@ func (c *Core) GetScan(ctx context.Context, pointer interface{}, sql string, arg
return c.db.GetCore().doGetStruct(ctx, pointer, sql, args...)
default:
}
return gerror.NewCodef(
gcode.CodeInvalidParameter,

View File

@ -53,7 +53,10 @@ func (r Record) Struct(pointer interface{}) error {
}
return nil
}
return gconv.StructTag(r, pointer, OrmTagForStruct)
return converter.Struct(r, pointer, gconv.StructOption{
PriorityTag: OrmTagForStruct,
ContinueOnError: true,
})
}
// IsEmpty checks and returns whether `r` is empty.

View File

@ -200,5 +200,12 @@ func (r Result) Structs(pointer interface{}) (err error) {
}
return nil
}
return gconv.StructsTag(r, pointer, OrmTagForStruct)
var (
sliceOption = gconv.SliceOption{ContinueOnError: true}
mapOption = gconv.StructOption{
PriorityTag: OrmTagForStruct,
ContinueOnError: true,
}
)
return converter.Structs(r, pointer, sliceOption, mapOption)
}

View File

@ -14,6 +14,15 @@ import (
"github.com/gogf/gf/v2/text/gregex"
)
func Test_GetConverter(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
c := GetConverter()
s, err := c.String(1)
t.AssertNil(err)
t.AssertEQ(s, "1")
})
}
func Test_HookSelect_Regex(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (

View File

@ -72,7 +72,7 @@ func New() *Client {
header: make(map[string]string),
cookies: make(map[string]string),
builder: gsel.GetBuilder(),
discovery: gsvc.GetRegistry(),
discovery: nil,
}
c.header[httpHeaderUserAgent] = defaultClientAgent
// It enables OpenTelemetry for client in default.

View File

@ -16,7 +16,6 @@ import (
"github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/net/gsel"
"github.com/gogf/gf/v2/net/gsvc"
"github.com/gogf/gf/v2/text/gstr"
)
type discoveryNode struct {
@ -39,7 +38,7 @@ var clientSelectorMap = gmap.New(true)
// internalMiddlewareDiscovery is a client middleware that enables service discovery feature for client.
func internalMiddlewareDiscovery(c *Client, r *http.Request) (response *Response, err error) {
if c.discovery == nil && !isServiceName(r.URL.Host) {
if c.discovery == nil {
return c.Next(r)
}
var (
@ -107,11 +106,3 @@ func updateSelectorNodesByService(ctx context.Context, selector gsel.Selector, s
}
return selector.Update(ctx, nodes)
}
// isServiceName checks and returns whether given input parameter is service name or not.
// It checks by whether the parameter is address by containing port delimiter character ':'.
//
// It does not contain any port number if using service discovery.
func isServiceName(serviceNameOrAddress string) bool {
return !gstr.Contains(serviceNameOrAddress, gsvc.EndpointHostPortDelimiter)
}

View File

@ -40,7 +40,7 @@ type Request struct {
// =================================================================================================================
handlers []*HandlerItemParsed // All matched handlers containing handler, hook and middleware for this request.
serveHandler *HandlerItemParsed // Real handler serving for this request, not hook or middleware.
serveHandler *HandlerItemParsed // Real business handler serving for this request, not hook or middleware handler.
handlerResponse interface{} // Handler response object for Request/Response handler.
hasHookHandler bool // A bool marking whether there's hook handler in the handlers for performance purpose.
hasServeHandler bool // A bool marking whether there's serving handler in the handlers for performance purpose.
@ -278,13 +278,3 @@ func (r *Request) ReloadParam() {
r.parsedQuery = false
r.bodyContent = nil
}
// GetHandlerResponse retrieves and returns the handler response object and its error.
func (r *Request) GetHandlerResponse() interface{} {
return r.handlerResponse
}
// GetServeHandler retrieves and returns the user defined handler used to serve this request.
func (r *Request) GetServeHandler() *HandlerItemParsed {
return r.serveHandler
}

View File

@ -10,6 +10,7 @@ import (
"bytes"
"fmt"
"io"
"mime"
"mime/multipart"
"net/http"
"reflect"
@ -107,7 +108,6 @@ func (r *Request) doParse(pointer interface{}, requestType int) error {
return err
}
}
// TODO: https://github.com/gogf/gf/pull/2450
// Validation.
if err = gvalid.New().
Bail().
@ -234,22 +234,46 @@ func (r *Request) parseBody() {
if r.ContentLength == 0 {
return
}
// If it's a multipart request, it does not parse the body content.
contentType := r.Header.Get("Content-Type")
if gstr.Contains(contentType, "multipart/") {
return
}
// Skip binary content types, which should not be parsed.
if r.isBinaryContentType(contentType) {
return
}
if body := r.GetBody(); len(body) > 0 {
// Trim space/new line characters.
body = bytes.TrimSpace(body)
// JSON format checks.
if body[0] == '{' && body[len(body)-1] == '}' {
// json/xml content type checks.
if gstr.Contains(contentType, "/json") {
_ = json.UnmarshalUseNumber(body, &r.bodyMap)
return
}
// XML format checks.
if len(body) > 5 && bytes.EqualFold(body[:5], xmlHeaderBytes) {
if gstr.Contains(contentType, "/xml") {
r.bodyMap, _ = gxml.DecodeWithoutRoot(body)
return
}
if body[0] == '<' && body[len(body)-1] == '>' {
r.bodyMap, _ = gxml.DecodeWithoutRoot(body)
// Auto decoding body content.
if r.Server.config.AutoDecodingBody {
// JSON format checks.
if body[0] == '{' && body[len(body)-1] == '}' {
_ = json.UnmarshalUseNumber(body, &r.bodyMap)
}
// XML format checks.
if len(body) > 5 && bytes.EqualFold(body[:5], xmlHeaderBytes) {
r.bodyMap, _ = gxml.DecodeWithoutRoot(body)
}
if body[0] == '<' && body[len(body)-1] == '>' {
r.bodyMap, _ = gxml.DecodeWithoutRoot(body)
}
}
// Default parameters decoding.
if contentType := r.Header.Get("Content-Type"); (contentType == "" || !gstr.Contains(contentType, "multipart/")) && r.bodyMap == nil {
if r.bodyMap == nil {
r.bodyMap, _ = gstr.Parse(r.GetBodyString())
}
}
@ -384,3 +408,42 @@ func (r *Request) GetMultipartFiles(name string) []*multipart.FileHeader {
}
return nil
}
// isBinaryContentType check the content type is binary or not.
func (r *Request) isBinaryContentType(contentType string) bool {
// parseMediaType
mimeType, _, err := mime.ParseMediaType(contentType)
// If the content type is invalid, it's treated as binary.
if err != nil {
return true
}
// Lowercase the MIME type for easier comparison
mimeType = strings.ToLower(mimeType)
// if the MIME type is text, then it's definitely not binary
if strings.HasPrefix(mimeType, "text/") {
return false
}
// defined non-binary MIME types
nonBinaryTypes := map[string]struct{}{
"application/json": {},
"application/xml": {},
"application/x-www-form-urlencoded": {},
"application/javascript": {},
"application/xhtml+xml": {},
}
if _, ok := nonBinaryTypes[mimeType]; ok {
return false
}
// if the MIME type is JSON or XML, it's definitely not binary
if strings.HasSuffix(mimeType, "+json") || strings.HasSuffix(mimeType, "+xml") {
return false
}
// otherwise, it's binary
// (this includes application/octet-stream、image/*、video/*、audio/*)
return true
}

View File

@ -0,0 +1,41 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package ghttp
import "github.com/gogf/gf/v2/util/gmeta"
// GetHandlerResponse retrieves and returns the handler response object and its error.
func (r *Request) GetHandlerResponse() interface{} {
return r.handlerResponse
}
// GetServeHandler retrieves and returns the user defined handler used to serve this request.
func (r *Request) GetServeHandler() *HandlerItemParsed {
return r.serveHandler
}
// GetMetaTag retrieves and returns the metadata value associated with the given key from the request struct.
// The meta value is from struct tags from g.Meta/gmeta.Meta type.
// For example:
//
// type GetMetaTagReq struct {
// g.Meta `path:"/test" method:"post" summary:"meta_tag" tags:"meta"`
// // ...
// }
//
// r.GetServeHandler().GetMetaTag("summary") // returns "meta_tag"
// r.GetServeHandler().GetMetaTag("method") // returns "post"
func (h *HandlerItemParsed) GetMetaTag(key string) string {
if h == nil || h.Handler == nil {
return ""
}
metaValue := gmeta.Get(h.Handler.Info.Type.In(1), key)
if metaValue != nil {
return metaValue.String()
}
return ""
}

View File

@ -8,7 +8,6 @@ package ghttp
import (
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/net/goai"
"github.com/gogf/gf/v2/os/gstructs"
"github.com/gogf/gf/v2/util/gconv"
@ -178,15 +177,17 @@ func (r *Request) doGetRequestStruct(pointer interface{}, mapping ...map[string]
if data == nil {
data = map[string]interface{}{}
}
// Default struct values.
if err = r.mergeDefaultStructValue(data, pointer); err != nil {
return data, nil
}
// `in` Tag Struct values.
if err = r.mergeInTagStructValue(data); err != nil {
return data, nil
}
// Default struct values.
if err = r.mergeDefaultStructValue(data, pointer); err != nil {
return data, nil
}
return data, gconv.Struct(data, pointer, mapping...)
}
@ -194,20 +195,9 @@ func (r *Request) doGetRequestStruct(pointer interface{}, mapping ...map[string]
func (r *Request) mergeDefaultStructValue(data map[string]interface{}, pointer interface{}) error {
fields := r.serveHandler.Handler.Info.ReqStructFields
if len(fields) > 0 {
var (
foundKey string
foundValue interface{}
)
for _, field := range fields {
if tagValue := field.TagDefault(); tagValue != "" {
foundKey, foundValue = gutil.MapPossibleItemByKey(data, field.Name())
if foundKey == "" {
data[field.Name()] = tagValue
} else {
if empty.IsEmpty(foundValue) {
data[foundKey] = tagValue
}
}
mergeTagValueWithFoundKey(data, false, field.Name(), field.Name(), tagValue)
}
}
return nil
@ -219,19 +209,8 @@ func (r *Request) mergeDefaultStructValue(data map[string]interface{}, pointer i
return err
}
if len(tagFields) > 0 {
var (
foundKey string
foundValue interface{}
)
for _, field := range tagFields {
foundKey, foundValue = gutil.MapPossibleItemByKey(data, field.Name())
if foundKey == "" {
data[field.Name()] = field.TagValue
} else {
if empty.IsEmpty(foundValue) {
data[foundKey] = field.TagValue
}
}
mergeTagValueWithFoundKey(data, false, field.Name(), field.Name(), field.TagValue)
}
}
@ -261,34 +240,29 @@ func (r *Request) mergeInTagStructValue(data map[string]interface{}) error {
for _, field := range fields {
if tagValue := field.TagIn(); tagValue != "" {
findKey := field.TagPriorityName()
switch tagValue {
case goai.ParameterInHeader:
foundHeaderKey, foundHeaderValue := gutil.MapPossibleItemByKey(headerMap, field.TagPriorityName())
if foundHeaderKey != "" {
foundKey, foundValue = gutil.MapPossibleItemByKey(data, foundHeaderKey)
if foundKey == "" {
data[field.Name()] = foundHeaderValue
} else {
if empty.IsEmpty(foundValue) {
data[foundKey] = foundHeaderValue
}
}
}
foundKey, foundValue = gutil.MapPossibleItemByKey(headerMap, findKey)
case goai.ParameterInCookie:
foundCookieKey, foundCookieValue := gutil.MapPossibleItemByKey(cookieMap, field.TagPriorityName())
if foundCookieKey != "" {
foundKey, foundValue = gutil.MapPossibleItemByKey(data, foundCookieKey)
if foundKey == "" {
data[field.Name()] = foundCookieValue
} else {
if empty.IsEmpty(foundValue) {
data[foundKey] = foundCookieValue
}
}
}
foundKey, foundValue = gutil.MapPossibleItemByKey(cookieMap, findKey)
}
if foundKey != "" {
mergeTagValueWithFoundKey(data, true, foundKey, field.Name(), foundValue)
}
}
}
}
return nil
}
// mergeTagValueWithFoundKey merges the request parameters when the key does not exist in the map or overwritten is true or the value is nil.
func mergeTagValueWithFoundKey(data map[string]interface{}, overwritten bool, findKey string, fieldName string, tagValue interface{}) {
if foundKey, foundValue := gutil.MapPossibleItemByKey(data, findKey); foundKey == "" {
data[fieldName] = tagValue
} else {
if overwritten || foundValue == nil {
data[foundKey] = tagValue
}
}
}

View File

@ -205,7 +205,7 @@ type ServerConfig struct {
// Logging.
// ======================================================================================================
Logger *glog.Logger `json:"logger"` // Logger specifies the logger for server.
Logger *glog.Logger `json:"logger"` // Logger directly specifies the logger for server.
LogPath string `json:"logPath"` // LogPath specifies the directory for storing logging files.
LogLevel string `json:"logLevel"` // LogLevel specifies the logging level for logger.
LogStdout bool `json:"logStdout"` // LogStdout specifies whether printing logging content to stdout.
@ -267,6 +267,9 @@ type ServerConfig struct {
// DumpRouterMap specifies whether automatically dumps router map when server starts.
DumpRouterMap bool `json:"dumpRouterMap"`
// AutoDecodingBody specifies whether automatically decodes request body using common encoding types: json/xml.
AutoDecodingBody bool `json:"auto_decoding_body"`
}
// NewConfig creates and returns a ServerConfig object with default configurations.
@ -313,6 +316,7 @@ func NewConfig() ServerConfig {
Graceful: false,
GracefulTimeout: 2, // seconds
GracefulShutdownTimeout: 5, // seconds
AutoDecodingBody: true,
}
}

View File

@ -286,6 +286,6 @@ func (item HandlerItem) MarshalJSON() ([]byte, error) {
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (item HandlerItemParsed) MarshalJSON() ([]byte, error) {
return json.Marshal(item.Handler)
func (h *HandlerItemParsed) MarshalJSON() ([]byte, error) {
return json.Marshal(h.Handler)
}

View File

@ -30,15 +30,15 @@ func Test_ConfigFromMap(t *testing.T) {
"readTimeout": "60s",
"indexFiles": g.Slice{"index.php", "main.php"},
"errorLogEnabled": true,
"cookieMaxAge": "1y",
"cookieMaxAge": "1d",
"cookieSameSite": "lax",
"cookieSecure": true,
"cookieHttpOnly": true,
}
config, err := ghttp.ConfigFromMap(m)
t.AssertNil(err)
d1, _ := time.ParseDuration(gconv.String(m["readTimeout"]))
d2, _ := time.ParseDuration(gconv.String(m["cookieMaxAge"]))
d1, _ := gtime.ParseDuration(gconv.String(m["readTimeout"]))
d2, _ := gtime.ParseDuration(gconv.String(m["cookieMaxAge"]))
t.Assert(config.Address, m["address"])
t.Assert(config.ReadTimeout, d1)
t.Assert(config.CookieMaxAge, d2)

View File

@ -13,34 +13,34 @@ import (
"github.com/gogf/gf/v2/util/guid"
)
type UserReq struct {
// UserTagInReq struct tag "in" supports: header, cookie
type UserTagInReq struct {
g.Meta `path:"/user" tags:"User" method:"post" summary:"user api" title:"api title"`
Id int `v:"required" d:"1"`
Name string `v:"required" in:"cookie"`
Age string `v:"required" in:"header"`
// header,query,cookie,form
}
type UserRes struct {
type UserTagInRes struct {
g.Meta `mime:"text/html" example:"string"`
}
var (
User = cUser{}
UserTagIn = cUserTagIn{}
)
type cUser struct{}
type cUserTagIn struct{}
func (c *cUser) User(ctx context.Context, req *UserReq) (res *UserRes, err error) {
func (c *cUserTagIn) User(ctx context.Context, req *UserTagInReq) (res *UserTagInRes, err error) {
g.RequestFromCtx(ctx).Response.WriteJson(req)
return
}
func Test_Params_Tag(t *testing.T) {
func Test_ParamsTagIn(t *testing.T) {
s := g.Server(guid.S())
s.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(ghttp.MiddlewareHandlerResponse)
group.Bind(User)
group.Bind(UserTagIn)
})
s.SetDumpRouterMap(false)
s.Start()
@ -56,17 +56,101 @@ func Test_Params_Tag(t *testing.T) {
client.SetHeader("age", "18")
t.Assert(client.PostContent(ctx, "/user"), `{"Id":1,"Name":"john","Age":"18"}`)
t.Assert(client.PostContent(ctx, "/user", "name=&age=&id="), `{"Id":1,"Name":"john","Age":"18"}`)
t.Assert(client.PostContent(ctx, "/user", "name=&age="), `{"Id":1,"Name":"john","Age":"18"}`)
})
}
func Benchmark_ParamTag(b *testing.B) {
type UserTagDefaultReq struct {
g.Meta `path:"/user-default" method:"post,get" summary:"user default tag api"`
Id int `v:"required" d:"1"`
Name string `d:"john"`
Age int `d:"18"`
Score float64 `d:"99.9"`
IsVip bool `d:"true"`
NickName string `p:"nickname" d:"nickname-default"`
EmptyStr string `d:""`
Email string
Address string
}
type UserTagDefaultRes struct {
g.Meta `mime:"application/json" example:"string"`
}
var (
UserTagDefault = cUserTagDefault{}
)
type cUserTagDefault struct{}
func (c *cUserTagDefault) User(ctx context.Context, req *UserTagDefaultReq) (res *UserTagDefaultRes, err error) {
g.RequestFromCtx(ctx).Response.WriteJson(req)
return
}
func Test_ParamsTagDefault(t *testing.T) {
s := g.Server(guid.S())
s.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(ghttp.MiddlewareHandlerResponse)
group.Bind(UserTagDefault)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
prefix := fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())
client := g.Client()
client.SetPrefix(prefix)
// Test with no parameters, should use all default values
resp := client.GetContent(ctx, "/user-default")
t.Assert(resp, `{"Id":1,"Name":"john","Age":18,"Score":99.9,"IsVip":true,"NickName":"nickname-default","EmptyStr":"","Email":"","Address":""}`)
// Test with partial parameters (query method), should use partial default values
resp = client.GetContent(ctx, "/user-default?id=100&name=smith")
t.Assert(resp, `{"Id":100,"Name":"smith","Age":18,"Score":99.9,"IsVip":true,"NickName":"nickname-default","EmptyStr":"","Email":"","Address":""}`)
// Test with partial parameters (query method), should use partial default values
resp = client.GetContent(ctx, "/user-default?id=100&name=smith&age")
t.Assert(resp, `{"Id":100,"Name":"smith","Age":18,"Score":99.9,"IsVip":true,"NickName":"nickname-default","EmptyStr":"","Email":"","Address":""}`)
// Test providing partial parameters via POST form
resp = client.PostContent(ctx, "/user-default", "id=200&age=30&nickname=jack")
t.Assert(resp, `{"Id":200,"Name":"john","Age":30,"Score":99.9,"IsVip":true,"NickName":"jack","EmptyStr":"","Email":"","Address":""}`)
// Test providing partial parameters via POST JSON
resp = client.ContentJson().PostContent(ctx, "/user-default", g.Map{
"id": 300,
"name": "bob",
"score": 88.8,
"address": "beijing",
})
t.Assert(resp, `{"Id":300,"Name":"bob","Age":18,"Score":88.8,"IsVip":true,"NickName":"nickname-default","EmptyStr":"","Email":"","Address":"beijing"}`)
// Test providing JSON content via GET request
resp = client.ContentJson().PostContent(ctx, "/user-default", `{"id":500,"isVip":false}`)
t.Assert(resp, `{"Id":500,"Name":"john","Age":18,"Score":99.9,"IsVip":false,"NickName":"nickname-default","EmptyStr":"","Email":"","Address":""}`)
// Test providing empty values, should use default values
resp = client.PostContent(ctx, "/user-default", "id=400&name=&age=")
t.Assert(resp, `{"Id":400,"Name":"","Age":0,"Score":99.9,"IsVip":true,"NickName":"nickname-default","EmptyStr":"","Email":"","Address":""}`)
// Test providing JSON content via GET request
resp = client.ContentJson().GetContent(ctx, "/user-default", `{"id":500,"isVip":false}`)
t.Assert(resp, `{"Id":500,"Name":"john","Age":18,"Score":99.9,"IsVip":false,"NickName":"nickname-default","EmptyStr":"","Email":"","Address":""}`)
})
}
func Benchmark_ParamTagIn(b *testing.B) {
b.StopTimer()
s := g.Server(guid.S())
s.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(ghttp.MiddlewareHandlerResponse)
group.Bind(User)
group.Bind(UserTagIn)
})
s.SetDumpRouterMap(false)
s.SetAccessLogEnabled(false)

View File

@ -8,6 +8,7 @@ package ghttp_test
import (
"bytes"
"context"
"fmt"
"io"
"testing"
@ -861,3 +862,44 @@ func Test_Params_GetRequestMapStrVar(t *testing.T) {
t.Assert(client.GetContent(ctx, "/GetRequestMapStrVar", "id=1"), 1)
})
}
type GetMetaTagReq struct {
g.Meta `path:"/test" method:"post" summary:"meta_tag" tags:"meta"`
Name string
}
type GetMetaTagRes struct{}
type GetMetaTagSt struct{}
func (r GetMetaTagSt) PostTest(ctx context.Context, req *GetMetaTagReq) (*GetMetaTagRes, error) {
return &GetMetaTagRes{}, nil
}
func TestRequest_GetServeHandler_GetMetaTag(t *testing.T) {
s := g.Server(guid.S())
s.Use(func(r *ghttp.Request) {
r.Response.Writef(
"summary:%s,method:%s",
r.GetServeHandler().GetMetaTag("summary"),
r.GetServeHandler().GetMetaTag("method"),
)
})
s.Group("/", func(grp *ghttp.RouterGroup) {
grp.Bind(GetMetaTagSt{})
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(1000 * time.Millisecond)
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
client := g.Client()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort()))
t.Assert(client.PostContent(ctx, "/test", "name=john"), "summary:meta_tag,method:post")
})
}

View File

@ -523,7 +523,7 @@ func Test_NullString_Issue3465(t *testing.T) {
"name": "null",
}
expect1 := `{"code":0,"message":"OK","data":{"name":null}}`
expect1 := `{"code":0,"message":"OK","data":{"name":["null"]}}`
t.Assert(client.GetContent(ctx, "/test", data1), expect1)
data2 := map[string]any{

View File

@ -678,3 +678,51 @@ func Test_Issue4047(t *testing.T) {
t.Assert(s.Logger(), nil)
})
}
// Issue4093Req
type Issue4093Req struct {
g.Meta `path:"/test" method:"post"`
Page int `json:"page" example:"10" d:"1" v:"min:1#页码最小值不能低于1" dc:"当前页码"`
PerPage int `json:"pageSize" example:"1" d:"10" v:"min:1|max:200#每页数量最小值不能低于1|最大值不能大于200" dc:"每页数量"`
Pagination bool `json:"pagination" d:"true" dc:"是否需要进行分页"`
Name string `json:"name" d:"john"`
Number int `json:"number" d:"1"`
}
type Issue4093Res struct {
g.Meta `mime:"text/html" example:"string"`
}
var (
Issue4093 = cIssue4093{}
)
type cIssue4093 struct{}
func (c *cIssue4093) User(ctx context.Context, req *Issue4093Req) (res *Issue4093Res, err error) {
g.RequestFromCtx(ctx).Response.WriteJson(req)
return
}
// https://github.com/gogf/gf/issues/4093
func Test_Issue4093(t *testing.T) {
s := g.Server(guid.S())
s.Group("/", func(group *ghttp.RouterGroup) {
group.Middleware(ghttp.MiddlewareHandlerResponse)
group.Bind(Issue4093)
})
s.SetDumpRouterMap(false)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
gtest.C(t, func(t *gtest.T) {
prefix := fmt.Sprintf("http://127.0.0.1:%d", s.GetListenedPort())
client := g.Client().ContentJson()
client.SetPrefix(prefix)
t.Assert(client.PostContent(ctx, "/test", `{"pagination":false,"name":"","number":0}`), `{"page":1,"pageSize":10,"pagination":false,"name":"","number":0}`)
t.Assert(client.PostContent(ctx, "/test"), `{"page":1,"pageSize":10,"pagination":true,"name":"john","number":1}`)
})
}

View File

@ -36,7 +36,7 @@ type Field struct {
type FieldsInput struct {
// Pointer should be type of struct/*struct.
// TODO this attribute name is not suitable, which would make confuse.
Pointer interface{}
Pointer any
// RecursiveOption specifies the way retrieving the fields recursively if the attribute
// is an embedded struct. It is RecursiveOptionNone in default.
@ -47,7 +47,7 @@ type FieldsInput struct {
type FieldMapInput struct {
// Pointer should be type of struct/*struct.
// TODO this attribute name is not suitable, which would make confuse.
Pointer interface{}
Pointer any
// PriorityTagArray specifies the priority tag array for retrieving from high to low.
// If it's given `nil`, it returns map[name]Field, of which the `name` is attribute name.
@ -123,6 +123,7 @@ func Fields(in FieldsInput) ([]Field, error) {
}
}
continue
default:
}
}
continue
@ -194,6 +195,7 @@ func FieldMap(in FieldMapInput) (map[string]Field, error) {
mapField[k] = tempV
}
}
default:
}
} else {
mapField[field.Name()] = tempField
@ -205,7 +207,19 @@ func FieldMap(in FieldMapInput) (map[string]Field, error) {
// StructType retrieves and returns the struct Type of specified struct/*struct.
// The parameter `object` should be either type of struct/*struct/[]struct/[]*struct.
func StructType(object interface{}) (*Type, error) {
func StructType(object any) (*Type, error) {
// if already reflect.Type
if reflectType, ok := object.(reflect.Type); ok {
for reflectType.Kind() == reflect.Ptr {
reflectType = reflectType.Elem()
}
if reflectType.Kind() == reflect.Struct {
return &Type{
Type: reflectType,
}, nil
}
}
var (
reflectValue reflect.Value
reflectKind reflect.Kind

View File

@ -10,16 +10,127 @@
package gconv
import (
"reflect"
"time"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv/internal/converter"
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
"github.com/gogf/gf/v2/util/gconv/internal/structcache"
)
// Converter is the manager for type converting.
type Converter interface {
ConverterForConvert
ConverterForRegister
ConverterForInt
ConverterForUint
ConverterForTime
ConverterForFloat
ConverterForMap
ConverterForSlice
ConverterForStruct
ConverterForBasic
}
// ConverterForBasic is the basic converting interface.
type ConverterForBasic interface {
Scan(srcValue, dstPointer any, option ScanOption) (err error)
String(any any) (string, error)
Bool(any any) (bool, error)
Rune(any any) (rune, error)
}
// ConverterForTime is the converting interface for time.
type ConverterForTime interface {
Time(v any, format ...string) (time.Time, error)
Duration(v any) (time.Duration, error)
GTime(v any, format ...string) (*gtime.Time, error)
}
// ConverterForInt is the converting interface for integer.
type ConverterForInt interface {
Int(v any) (int, error)
Int8(v any) (int8, error)
Int16(v any) (int16, error)
Int32(v any) (int32, error)
Int64(v any) (int64, error)
}
// ConverterForUint is the converting interface for unsigned integer.
type ConverterForUint interface {
Uint(v any) (uint, error)
Uint8(v any) (uint8, error)
Uint16(v any) (uint16, error)
Uint32(v any) (uint32, error)
Uint64(v any) (uint64, error)
}
// ConverterForFloat is the converting interface for float.
type ConverterForFloat interface {
Float32(v any) (float32, error)
Float64(v any) (float64, error)
}
// ConverterForMap is the converting interface for map.
type ConverterForMap interface {
Map(v any, option MapOption) (map[string]any, error)
MapStrStr(v any, option MapOption) (map[string]string, error)
}
// ConverterForSlice is the converting interface for slice.
type ConverterForSlice interface {
Bytes(v any) ([]byte, error)
Runes(v any) ([]rune, error)
SliceAny(v any, option SliceOption) ([]any, error)
SliceFloat32(v any, option SliceOption) ([]float32, error)
SliceFloat64(v any, option SliceOption) ([]float64, error)
SliceInt(v any, option SliceOption) ([]int, error)
SliceInt32(v any, option SliceOption) ([]int32, error)
SliceInt64(v any, option SliceOption) ([]int64, error)
SliceUint(v any, option SliceOption) ([]uint, error)
SliceUint32(v any, option SliceOption) ([]uint32, error)
SliceUint64(v any, option SliceOption) ([]uint64, error)
SliceStr(v any, option SliceOption) ([]string, error)
SliceMap(v any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error)
}
// ConverterForStruct is the converting interface for struct.
type ConverterForStruct interface {
Struct(params, pointer any, option StructOption) (err error)
Structs(params, pointer any, sliceOption SliceOption, structOption StructOption) (err error)
}
// ConverterForConvert is the converting interface for custom converting.
type ConverterForConvert interface {
ConvertWithRefer(fromValue, referValue any, option ConvertOption) (any, error)
ConvertWithTypeName(fromValue any, toTypeName string, option ConvertOption) (any, error)
}
// ConverterForRegister is the converting interface for custom converter registration.
type ConverterForRegister interface {
RegisterTypeConverterFunc(f any) error
RegisterAnyConverterFunc(f AnyConvertFunc, types ...reflect.Type)
}
type (
// AnyConvertFunc is the function type for converting any to specified type.
AnyConvertFunc = structcache.AnyConvertFunc
MapOption = converter.MapOption
ScanOption = converter.ScanOption
SliceOption = converter.SliceOption
// MapOption specifies the option for map converting.
MapOption = converter.MapOption
// SliceOption is the option for Slice type converting.
SliceOption = converter.SliceOption
// ScanOption is the option for the Scan function.
ScanOption = converter.ScanOption
// StructOption is the option for Struct converting.
StructOption = converter.StructOption
// ConvertOption is the option for converting.
ConvertOption = converter.ConvertOption
)
// IUnmarshalValue is the interface for custom defined types customizing value assignment.
@ -31,6 +142,16 @@ var (
defaultConverter = converter.NewConverter()
)
// RegisterAnyConverterFunc registers custom type converting function for specified type.
func RegisterAnyConverterFunc(f AnyConvertFunc, types ...reflect.Type) {
defaultConverter.RegisterAnyConverterFunc(f, types...)
}
// NewConverter creates and returns management object for type converting.
func NewConverter() Converter {
return converter.NewConverter()
}
// RegisterConverter registers custom converter.
// Deprecated: use RegisterTypeConverterFunc instead for clear
func RegisterConverter(fn any) (err error) {

View File

@ -11,7 +11,12 @@ package gconv
// The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
// It supports common basic types conversion as its conversion based on type name string.
func Convert(fromValue any, toTypeName string, extraParams ...any) any {
result, _ := defaultConverter.ConvertWithTypeName(fromValue, toTypeName, extraParams...)
result, _ := defaultConverter.ConvertWithTypeName(fromValue, toTypeName, ConvertOption{
ExtraParams: extraParams,
SliceOption: SliceOption{ContinueOnError: true},
MapOption: MapOption{ContinueOnError: true},
StructOption: StructOption{ContinueOnError: true},
})
return result
}
@ -20,6 +25,11 @@ func Convert(fromValue any, toTypeName string, extraParams ...any) any {
// The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
// It supports common basic types conversion as its conversion based on type name string.
func ConvertWithRefer(fromValue any, referValue any, extraParams ...any) any {
result, _ := defaultConverter.ConvertWithRefer(fromValue, referValue, extraParams...)
result, _ := defaultConverter.ConvertWithRefer(fromValue, referValue, ConvertOption{
ExtraParams: extraParams,
SliceOption: SliceOption{ContinueOnError: true},
MapOption: MapOption{ContinueOnError: true},
StructOption: StructOption{ContinueOnError: true},
})
return result
}

View File

@ -23,10 +23,10 @@ func Map(value any, option ...MapOption) map[string]any {
// Deprecated: used Map instead.
func MapDeep(value any, tags ...string) map[string]any {
result, _ := defaultConverter.Map(value, MapOption{
Deep: true,
OmitEmpty: false,
Tags: tags,
BreakOnError: false,
Deep: true,
OmitEmpty: false,
Tags: tags,
ContinueOnError: true,
})
return result
}
@ -57,7 +57,9 @@ func MapStrStrDeep(value any, tags ...string) map[string]string {
}
func getUsedMapOption(option ...MapOption) MapOption {
var usedOption MapOption
var usedOption = MapOption{
ContinueOnError: true,
}
if len(option) > 0 {
usedOption = option[0]
}

View File

@ -9,72 +9,42 @@ package gconv
import "github.com/gogf/gf/v2/internal/json"
// SliceMap is alias of Maps.
func SliceMap(any interface{}, option ...MapOption) []map[string]interface{} {
func SliceMap(any any, option ...MapOption) []map[string]any {
return Maps(any, option...)
}
// SliceMapDeep is alias of MapsDeep.
// Deprecated: used SliceMap instead.
func SliceMapDeep(any interface{}) []map[string]interface{} {
func SliceMapDeep(any any) []map[string]any {
return MapsDeep(any)
}
// Maps converts `value` to []map[string]interface{}.
// Maps converts `value` to []map[string]any.
// Note that it automatically checks and converts json string to []map if `value` is string/[]byte.
func Maps(value interface{}, option ...MapOption) []map[string]interface{} {
if value == nil {
return nil
func Maps(value any, option ...MapOption) []map[string]any {
mapOption := MapOption{
ContinueOnError: true,
}
switch r := value.(type) {
case string:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.UnmarshalUseNumber([]byte(r), &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []byte:
list := make([]map[string]interface{}, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.UnmarshalUseNumber(r, &list); err != nil {
return nil
}
return list
} else {
return nil
}
case []map[string]interface{}:
return r
default:
array := Interfaces(value)
if len(array) == 0 {
return nil
}
list := make([]map[string]interface{}, len(array))
for k, v := range array {
list[k] = Map(v, option...)
}
return list
if len(option) > 0 {
mapOption = option[0]
}
result, _ := defaultConverter.SliceMap(value, SliceOption{
ContinueOnError: true,
}, mapOption)
return result
}
// MapsDeep converts `value` to []map[string]interface{} recursively.
// MapsDeep converts `value` to []map[string]any recursively.
//
// TODO completely implement the recursive converting for all types.
// Deprecated: used Maps instead.
func MapsDeep(value interface{}, tags ...string) []map[string]interface{} {
func MapsDeep(value any, tags ...string) []map[string]any {
if value == nil {
return nil
}
switch r := value.(type) {
case string:
list := make([]map[string]interface{}, 0)
list := make([]map[string]any, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.UnmarshalUseNumber([]byte(r), &list); err != nil {
return nil
@ -85,7 +55,7 @@ func MapsDeep(value interface{}, tags ...string) []map[string]interface{} {
}
case []byte:
list := make([]map[string]interface{}, 0)
list := make([]map[string]any, 0)
if len(r) > 0 && r[0] == '[' && r[len(r)-1] == ']' {
if err := json.UnmarshalUseNumber(r, &list); err != nil {
return nil
@ -95,8 +65,8 @@ func MapsDeep(value interface{}, tags ...string) []map[string]interface{} {
return nil
}
case []map[string]interface{}:
list := make([]map[string]interface{}, len(r))
case []map[string]any:
list := make([]map[string]any, len(r))
for k, v := range r {
list[k] = MapDeep(v, tags...)
}
@ -107,7 +77,7 @@ func MapsDeep(value interface{}, tags ...string) []map[string]interface{} {
if len(array) == 0 {
return nil
}
list := make([]map[string]interface{}, len(array))
list := make([]map[string]any, len(array))
for k, v := range array {
list[k] = MapDeep(v, tags...)
}

View File

@ -17,7 +17,9 @@ package gconv
// The `paramKeyToAttrMap` parameter is used for mapping between attribute names and parameter keys.
// TODO: change `paramKeyToAttrMap` to `ScanOption` to be more scalable; add `DeepCopy` option for `ScanOption`.
func Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error) {
option := ScanOption{}
option := ScanOption{
ContinueOnError: true,
}
if len(paramKeyToAttrMap) > 0 {
option.ParamKeyToAttrMap = paramKeyToAttrMap[0]
}

View File

@ -93,7 +93,9 @@ import (
// given `relation` parameter.
//
// See the example or unit testing cases for clear understanding for this function.
func ScanList(structSlice interface{}, structSlicePointer interface{}, bindToAttrName string, relationAttrNameAndFields ...string) (err error) {
func ScanList(
structSlice any, structSlicePointer any, bindToAttrName string, relationAttrNameAndFields ...string,
) (err error) {
var (
relationAttrName string
relationFields string
@ -111,7 +113,7 @@ func ScanList(structSlice interface{}, structSlicePointer interface{}, bindToAtt
// doScanList converts `structSlice` to struct slice which contains other complex struct attributes recursively.
// Note that the parameter `structSlicePointer` should be type of *[]struct/*[]*struct.
func doScanList(
structSlice interface{}, structSlicePointer interface{}, bindToAttrName, relationAttrName, relationFields string,
structSlice any, structSlicePointer any, bindToAttrName, relationAttrName, relationFields string,
) (err error) {
var (
maps = Maps(structSlice)
@ -169,7 +171,7 @@ func doScanList(
// Relation variables.
var (
relationDataMap map[string]interface{}
relationDataMap map[string]any
relationFromFieldName string // Eg: relationKV: id:uid -> id
relationBindToFieldName string // Eg: relationKV: id:uid -> uid
)
@ -315,7 +317,7 @@ func doScanList(
relationFromAttrField = relationFromAttrValue.FieldByName(relationBindToFieldName)
if relationFromAttrField.IsValid() {
// results := make(Result, 0)
results := make([]interface{}, 0)
results := make([]any, 0)
for _, v := range SliceAny(relationDataMap[String(relationFromAttrField.Interface())]) {
item := v
results = append(results, item)

View File

@ -13,6 +13,8 @@ func SliceAny(any interface{}) []interface{} {
// Interfaces converts `any` to []interface{}.
func Interfaces(any interface{}) []interface{} {
result, _ := defaultConverter.SliceAny(any, SliceOption{})
result, _ := defaultConverter.SliceAny(any, SliceOption{
ContinueOnError: true,
})
return result
}

View File

@ -28,12 +28,16 @@ func Floats(any interface{}) []float64 {
// Float32s converts `any` to []float32.
func Float32s(any interface{}) []float32 {
result, _ := defaultConverter.SliceFloat32(any, SliceOption{})
result, _ := defaultConverter.SliceFloat32(any, SliceOption{
ContinueOnError: true,
})
return result
}
// Float64s converts `any` to []float64.
func Float64s(any interface{}) []float64 {
result, _ := defaultConverter.SliceFloat64(any, SliceOption{})
result, _ := defaultConverter.SliceFloat64(any, SliceOption{
ContinueOnError: true,
})
return result
}

View File

@ -23,18 +23,24 @@ func SliceInt64(any any) []int64 {
// Ints converts `any` to []int.
func Ints(any any) []int {
result, _ := defaultConverter.SliceInt(any, SliceOption{})
result, _ := defaultConverter.SliceInt(any, SliceOption{
ContinueOnError: true,
})
return result
}
// Int32s converts `any` to []int32.
func Int32s(any any) []int32 {
result, _ := defaultConverter.SliceInt32(any, SliceOption{})
result, _ := defaultConverter.SliceInt32(any, SliceOption{
ContinueOnError: true,
})
return result
}
// Int64s converts `any` to []int64.
func Int64s(any any) []int64 {
result, _ := defaultConverter.SliceInt64(any, SliceOption{})
result, _ := defaultConverter.SliceInt64(any, SliceOption{
ContinueOnError: true,
})
return result
}

View File

@ -13,6 +13,8 @@ func SliceStr(any interface{}) []string {
// Strings converts `any` to []string.
func Strings(any interface{}) []string {
result, _ := defaultConverter.SliceStr(any, SliceOption{})
result, _ := defaultConverter.SliceStr(any, SliceOption{
ContinueOnError: true,
})
return result
}

View File

@ -23,18 +23,24 @@ func SliceUint64(any interface{}) []uint64 {
// Uints converts `any` to []uint.
func Uints(any interface{}) []uint {
result, _ := defaultConverter.SliceUint(any, SliceOption{})
result, _ := defaultConverter.SliceUint(any, SliceOption{
ContinueOnError: true,
})
return result
}
// Uint32s converts `any` to []uint32.
func Uint32s(any interface{}) []uint32 {
result, _ := defaultConverter.SliceUint32(any, SliceOption{})
result, _ := defaultConverter.SliceUint32(any, SliceOption{
ContinueOnError: true,
})
return result
}
// Uint64s converts `any` to []uint64.
func Uint64s(any interface{}) []uint64 {
result, _ := defaultConverter.SliceUint64(any, SliceOption{})
result, _ := defaultConverter.SliceUint64(any, SliceOption{
ContinueOnError: true,
})
return result
}

View File

@ -27,5 +27,9 @@ func Struct(params any, pointer any, paramKeyToAttrMap ...map[string]string) (er
// specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping.
// The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','.
func StructTag(params any, pointer any, priorityTag string) (err error) {
return defaultConverter.Struct(params, pointer, nil, priorityTag)
option := StructOption{
PriorityTag: priorityTag,
ContinueOnError: true,
}
return defaultConverter.Struct(params, pointer, option)
}

View File

@ -21,5 +21,10 @@ func SliceStruct(params any, pointer any, mapping ...map[string]string) (err err
// specified priorityTagAndFieldName for `params` key-value items to struct attribute names mapping.
// The parameter `priorityTag` supports multiple priorityTagAndFieldName that can be joined with char ','.
func StructsTag(params any, pointer any, priorityTag string) (err error) {
return defaultConverter.Structs(params, pointer, nil, priorityTag)
return defaultConverter.Structs(params, pointer, SliceOption{
ContinueOnError: true,
}, StructOption{
PriorityTag: priorityTag,
ContinueOnError: true,
})
}

View File

@ -92,7 +92,7 @@ func Benchmark_Struct_Basic(b *testing.B) {
func Benchmark_doStruct_Fields8_Basic_MapToStruct(b *testing.B) {
for i := 0; i < b.N; i++ {
defaultConverter.Struct(structMapFields8, structPointer8, map[string]string{}, "")
defaultConverter.Struct(structMapFields8, structPointer8, StructOption{})
}
}

View File

@ -7,6 +7,9 @@
package gconv_test
import (
"database/sql"
"fmt"
"reflect"
"testing"
"github.com/gogf/gf/v2/test/gtest"
@ -84,3 +87,87 @@ func TestConvertWithRefer(t *testing.T) {
t.AssertNE(gconv.ConvertWithRefer("1.01", false), false)
})
}
func testAnyToMyInt(from any, to reflect.Value) error {
switch x := from.(type) {
case int:
to.SetInt(123456)
default:
return fmt.Errorf("unsupported type %T(%v)", x, x)
}
return nil
}
func testAnyToSqlNullType(_ any, to reflect.Value) error {
if to.Kind() != reflect.Ptr {
to = to.Addr()
}
return to.Interface().(sql.Scanner).Scan(123456)
}
func TestNewConverter(t *testing.T) {
type Dst[T any] struct {
A T
}
gtest.C(t, func(t *gtest.T) {
conv := gconv.NewConverter()
conv.RegisterAnyConverterFunc(testAnyToMyInt, reflect.TypeOf((*myInt)(nil)))
var dst Dst[myInt]
err := conv.Struct(map[string]any{
"a": 1200,
}, &dst, gconv.StructOption{})
t.AssertNil(err)
t.Assert(dst, Dst[myInt]{
A: 123456,
})
})
gtest.C(t, func(t *gtest.T) {
conv := gconv.NewConverter()
conv.RegisterAnyConverterFunc(testAnyToMyInt, reflect.TypeOf((myInt)(0)))
var dst Dst[*myInt]
err := conv.Struct(map[string]any{
"a": 1200,
}, &dst, gconv.StructOption{})
t.AssertNil(err)
t.Assert(*dst.A, 123456)
})
gtest.C(t, func(t *gtest.T) {
conv := gconv.NewConverter()
conv.RegisterAnyConverterFunc(testAnyToSqlNullType, reflect.TypeOf((*sql.Scanner)(nil)))
type sqlNullDst struct {
A sql.Null[int]
B sql.Null[float32]
C sql.NullInt64
D sql.NullString
E *sql.Null[int]
F *sql.Null[float32]
G *sql.NullInt64
H *sql.NullString
}
var dst sqlNullDst
err := conv.Struct(map[string]any{
"a": 12,
"b": 34,
"c": 56,
"d": "sqlNullString",
"e": 12,
"f": 34,
"g": 56,
"h": "sqlNullString",
}, &dst, gconv.StructOption{})
t.AssertNil(err)
t.Assert(dst, sqlNullDst{
A: sql.Null[int]{V: 123456, Valid: true},
B: sql.Null[float32]{V: 123456, Valid: true},
C: sql.NullInt64{Int64: 123456, Valid: true},
D: sql.NullString{String: "123456", Valid: true},
E: &sql.Null[int]{V: 123456, Valid: true},
F: &sql.Null[float32]{V: 123456, Valid: true},
G: &sql.NullInt64{Int64: 123456, Valid: true},
H: &sql.NullString{String: "123456", Valid: true},
})
})
}

View File

@ -4,6 +4,7 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package converter provides converting utilities for any types of variables.
package converter
import (
@ -16,8 +17,10 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/structcache"
)
// AnyConvertFunc is the type for any type converting function.
type AnyConvertFunc = structcache.AnyConvertFunc
// RecursiveType is the type for converting recursively.
type RecursiveType string
const (
@ -31,45 +34,8 @@ type (
converterFunc = reflect.Value
)
// Converter is the manager for type converting.
type Converter interface {
RegisterTypeConverterFunc(fn any) (err error)
ConverterForInt
ConverterForUint
String(any any) (string, error)
Bool(any any) (bool, error)
Bytes(any any) ([]byte, error)
Float32(any any) (float32, error)
Float64(any any) (float64, error)
MapToMap(params any, pointer any, mapping ...map[string]string) (err error)
MapToMaps(params any, pointer any, paramKeyToAttrMap ...map[string]string) (err error)
Rune(any any) (rune, error)
Runes(any any) ([]rune, error)
Scan(srcValue any, dstPointer any, paramKeyToAttrMap ...map[string]string) (err error)
Time(any interface{}, format ...string) (time.Time, error)
Duration(any interface{}) (time.Duration, error)
GTime(any interface{}, format ...string) (*gtime.Time, error)
}
type ConverterForInt interface {
Int(any any) (int, error)
Int8(any any) (int8, error)
Int16(any any) (int16, error)
Int32(any any) (int32, error)
Int64(any any) (int64, error)
}
type ConverterForUint interface {
Uint(any any) (uint, error)
Uint8(any any) (uint8, error)
Uin16(any any) (uint16, error)
Uint32(any any) (uint32, error)
Uint64(any any) (uint64, error)
}
// impConverter implements the interface Converter.
type impConverter struct {
// Converter implements the interface Converter.
type Converter struct {
internalConverter *structcache.Converter
typeConverterFuncMap map[converterInType]map[converterOutType]converterFunc
}
@ -83,38 +49,15 @@ var (
"off": {},
"false": {},
}
intType = reflect.TypeOf(0)
int8Type = reflect.TypeOf(int8(0))
int16Type = reflect.TypeOf(int16(0))
int32Type = reflect.TypeOf(int32(0))
int64Type = reflect.TypeOf(int64(0))
uintType = reflect.TypeOf(uint(0))
uint8Type = reflect.TypeOf(uint8(0))
uint16Type = reflect.TypeOf(uint16(0))
uint32Type = reflect.TypeOf(uint32(0))
uint64Type = reflect.TypeOf(uint64(0))
float32Type = reflect.TypeOf(float32(0))
float64Type = reflect.TypeOf(float64(0))
stringType = reflect.TypeOf("")
bytesType = reflect.TypeOf([]byte{})
boolType = reflect.TypeOf(false)
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
gtimeType = reflect.TypeOf((*gtime.Time)(nil)).Elem()
)
// NewConverter creates and returns management object for type converting.
func NewConverter() *impConverter {
cf := &impConverter{
func NewConverter() *Converter {
cf := &Converter{
internalConverter: structcache.NewConverter(),
typeConverterFuncMap: make(map[converterInType]map[converterOutType]converterFunc),
}
cf.registerBuiltInConverter()
cf.registerBuiltInAnyConvertFunc()
return cf
}
@ -126,33 +69,33 @@ func NewConverter() *impConverter {
// 1. The parameter `fn` must be defined as pattern `func(T1) (T2, error)`.
// It will convert type `T1` to type `T2`.
// 2. The `T1` should not be type of pointer, but the `T2` should be type of pointer.
func (c *impConverter) RegisterTypeConverterFunc(fn any) (err error) {
func (c *Converter) RegisterTypeConverterFunc(f any) (err error) {
var (
fnReflectType = reflect.TypeOf(fn)
errType = reflect.TypeOf((*error)(nil)).Elem()
fReflectType = reflect.TypeOf(f)
errType = reflect.TypeOf((*error)(nil)).Elem()
)
if fnReflectType.Kind() != reflect.Func ||
fnReflectType.NumIn() != 1 || fnReflectType.NumOut() != 2 ||
!fnReflectType.Out(1).Implements(errType) {
if fReflectType.Kind() != reflect.Func ||
fReflectType.NumIn() != 1 || fReflectType.NumOut() != 2 ||
!fReflectType.Out(1).Implements(errType) {
err = gerror.NewCodef(
gcode.CodeInvalidParameter,
"parameter must be type of converter function and defined as pattern `func(T1) (T2, error)`, "+
"but defined as `%s`",
fnReflectType.String(),
fReflectType.String(),
)
return
}
// The Key and Value of the converter map should not be pointer.
var (
inType = fnReflectType.In(0)
outType = fnReflectType.Out(0)
inType = fReflectType.In(0)
outType = fReflectType.Out(0)
)
if inType.Kind() == reflect.Pointer {
err = gerror.NewCodef(
gcode.CodeInvalidParameter,
"invalid converter function `%s`: invalid input parameter type `%s`, should not be type of pointer",
fnReflectType.String(), inType.String(),
fReflectType.String(), inType.String(),
)
return
}
@ -160,7 +103,7 @@ func (c *impConverter) RegisterTypeConverterFunc(fn any) (err error) {
err = gerror.NewCodef(
gcode.CodeInvalidParameter,
"invalid converter function `%s`: invalid output parameter type `%s` should be type of pointer",
fnReflectType.String(), outType.String(),
fReflectType.String(), outType.String(),
)
return
}
@ -178,40 +121,60 @@ func (c *impConverter) RegisterTypeConverterFunc(fn any) (err error) {
)
return
}
registeredOutTypeMap[outType] = reflect.ValueOf(fn)
c.internalConverter.RegisterTypeConvertFunc(outType)
registeredOutTypeMap[outType] = reflect.ValueOf(f)
c.internalConverter.MarkTypeConvertFunc(outType)
return
}
func (c *impConverter) registerBuiltInConverter() {
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForString, stringType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForFloat64, float32Type, float64Type,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForBool, boolType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForBytes, bytesType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForTime, timeType,
)
c.registerAnyConvertFuncForTypes(
c.builtInAnyConvertFuncForGTime, gtimeType,
)
}
func (c *impConverter) registerAnyConvertFuncForTypes(convertFunc AnyConvertFunc, types ...reflect.Type) {
// RegisterAnyConverterFunc registers custom type converting function for specified types.
func (c *Converter) RegisterAnyConverterFunc(convertFunc AnyConvertFunc, types ...reflect.Type) {
for _, t := range types {
c.internalConverter.RegisterAnyConvertFunc(t, convertFunc)
}
}
func (c *Converter) registerBuiltInAnyConvertFunc() {
var (
intType = reflect.TypeOf(0)
int8Type = reflect.TypeOf(int8(0))
int16Type = reflect.TypeOf(int16(0))
int32Type = reflect.TypeOf(int32(0))
int64Type = reflect.TypeOf(int64(0))
uintType = reflect.TypeOf(uint(0))
uint8Type = reflect.TypeOf(uint8(0))
uint16Type = reflect.TypeOf(uint16(0))
uint32Type = reflect.TypeOf(uint32(0))
uint64Type = reflect.TypeOf(uint64(0))
float32Type = reflect.TypeOf(float32(0))
float64Type = reflect.TypeOf(float64(0))
stringType = reflect.TypeOf("")
bytesType = reflect.TypeOf([]byte{})
boolType = reflect.TypeOf(false)
timeType = reflect.TypeOf((*time.Time)(nil)).Elem()
gtimeType = reflect.TypeOf((*gtime.Time)(nil)).Elem()
)
c.RegisterAnyConverterFunc(
c.builtInAnyConvertFuncForInt64, intType, int8Type, int16Type, int32Type, int64Type,
)
c.RegisterAnyConverterFunc(
c.builtInAnyConvertFuncForUint64, uintType, uint8Type, uint16Type, uint32Type, uint64Type,
)
c.RegisterAnyConverterFunc(
c.builtInAnyConvertFuncForString, stringType,
)
c.RegisterAnyConverterFunc(
c.builtInAnyConvertFuncForFloat64, float32Type, float64Type,
)
c.RegisterAnyConverterFunc(
c.builtInAnyConvertFuncForBool, boolType,
)
c.RegisterAnyConverterFunc(
c.builtInAnyConvertFuncForBytes, bytesType,
)
c.RegisterAnyConverterFunc(
c.builtInAnyConvertFuncForTime, timeType,
)
c.RegisterAnyConverterFunc(
c.builtInAnyConvertFuncForGTime, gtimeType,
)
}

View File

@ -15,7 +15,7 @@ import (
)
// Bool converts `any` to bool.
func (c *impConverter) Bool(any any) (bool, error) {
func (c *Converter) Bool(any any) (bool, error) {
if empty.IsNil(any) {
return false, nil
}

View File

@ -13,7 +13,7 @@ import (
"github.com/gogf/gf/v2/os/gtime"
)
func (c *impConverter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error {
func (c *Converter) builtInAnyConvertFuncForInt64(from any, to reflect.Value) error {
v, err := c.Int64(from)
if err != nil {
return err
@ -22,7 +22,7 @@ func (c *impConverter) builtInAnyConvertFuncForInt64(from any, to reflect.Value)
return nil
}
func (c *impConverter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error {
func (c *Converter) builtInAnyConvertFuncForUint64(from any, to reflect.Value) error {
v, err := c.Uint64(from)
if err != nil {
return err
@ -31,7 +31,7 @@ func (c *impConverter) builtInAnyConvertFuncForUint64(from any, to reflect.Value
return nil
}
func (c *impConverter) builtInAnyConvertFuncForString(from any, to reflect.Value) error {
func (c *Converter) builtInAnyConvertFuncForString(from any, to reflect.Value) error {
v, err := c.String(from)
if err != nil {
return err
@ -40,7 +40,7 @@ func (c *impConverter) builtInAnyConvertFuncForString(from any, to reflect.Value
return nil
}
func (c *impConverter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error {
func (c *Converter) builtInAnyConvertFuncForFloat64(from any, to reflect.Value) error {
v, err := c.Float64(from)
if err != nil {
return err
@ -49,7 +49,7 @@ func (c *impConverter) builtInAnyConvertFuncForFloat64(from any, to reflect.Valu
return nil
}
func (c *impConverter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error {
func (c *Converter) builtInAnyConvertFuncForBool(from any, to reflect.Value) error {
v, err := c.Bool(from)
if err != nil {
return err
@ -58,7 +58,7 @@ func (c *impConverter) builtInAnyConvertFuncForBool(from any, to reflect.Value)
return nil
}
func (c *impConverter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error {
func (c *Converter) builtInAnyConvertFuncForBytes(from any, to reflect.Value) error {
v, err := c.Bytes(from)
if err != nil {
return err
@ -67,7 +67,7 @@ func (c *impConverter) builtInAnyConvertFuncForBytes(from any, to reflect.Value)
return nil
}
func (c *impConverter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error {
func (c *Converter) builtInAnyConvertFuncForTime(from any, to reflect.Value) error {
t, err := c.Time(from)
if err != nil {
return err
@ -76,7 +76,7 @@ func (c *impConverter) builtInAnyConvertFuncForTime(from any, to reflect.Value)
return nil
}
func (c *impConverter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error {
func (c *Converter) builtInAnyConvertFuncForGTime(from any, to reflect.Value) error {
v, err := c.GTime(from)
if err != nil {
return err

View File

@ -17,7 +17,8 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *impConverter) Bytes(any any) ([]byte, error) {
// Bytes converts `any` to []byte.
func (c *Converter) Bytes(any any) ([]byte, error) {
if empty.IsNil(any) {
return nil, nil
}

View File

@ -14,45 +14,49 @@ import (
"github.com/gogf/gf/v2/os/gtime"
)
// ConvertOption is the option for converting.
type ConvertOption struct {
// ExtraParams are extra values for implementing the converting.
ExtraParams []any
SliceOption SliceOption
MapOption MapOption
StructOption StructOption
}
// ConvertWithTypeName converts the variable `fromValue` to the type `toTypeName`, the type `toTypeName` is specified by string.
//
// The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
// It supports common basic types conversion as its conversion based on type name string.
func (c *impConverter) ConvertWithTypeName(fromValue any, toTypeName string, extraParams ...any) (any, error) {
func (c *Converter) ConvertWithTypeName(fromValue any, toTypeName string, option ConvertOption) (any, error) {
return c.doConvert(
doConvertInput{
FromValue: fromValue,
ToTypeName: toTypeName,
ReferValue: nil,
Extra: extraParams,
},
option,
)
}
// ConvertWithRefer converts the variable `fromValue` to the type referred by value `referValue`.
//
// The optional parameter `extraParams` is used for additional necessary parameter for this conversion.
// It supports common basic types conversion as its conversion based on type name string.
func (c *impConverter) ConvertWithRefer(fromValue, referValue any, extraParams ...any) (any, error) {
func (c *Converter) ConvertWithRefer(fromValue, referValue any, option ConvertOption) (any, error) {
var referValueRf reflect.Value
if v, ok := referValue.(reflect.Value); ok {
referValueRf = v
} else {
referValueRf = reflect.ValueOf(referValue)
}
return c.doConvert(doConvertInput{
FromValue: fromValue,
ToTypeName: referValueRf.Type().String(),
ReferValue: referValue,
Extra: extraParams,
})
return c.doConvert(
doConvertInput{
FromValue: fromValue,
ToTypeName: referValueRf.Type().String(),
ReferValue: referValue,
},
option,
)
}
type doConvertInput struct {
FromValue any // Value that is converted from.
ToTypeName string // Target value type name in string.
ReferValue any // Referred value, a value in type `ToTypeName`. Note that its type might be reflect.Value.
Extra []any // Extra values for implementing the converting.
// Marks that the value is already converted and set to `ReferValue`. Caller can ignore the returned result.
// It is an attribute for internal usage purpose.
@ -60,7 +64,7 @@ type doConvertInput struct {
}
// doConvert does commonly use types converting.
func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err error) {
func (c *Converter) doConvert(in doConvertInput, option ConvertOption) (convertedValue any, err error) {
switch in.ToTypeName {
case "int":
return c.Int(in.FromValue)
@ -233,29 +237,29 @@ func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err err
case "[]byte":
return c.Bytes(in.FromValue)
case "[]int":
return c.SliceInt(in.FromValue, SliceOption{})
return c.SliceInt(in.FromValue, option.SliceOption)
case "[]int32":
return c.SliceInt32(in.FromValue, SliceOption{})
return c.SliceInt32(in.FromValue, option.SliceOption)
case "[]int64":
return c.SliceInt64(in.FromValue, SliceOption{})
return c.SliceInt64(in.FromValue, option.SliceOption)
case "[]uint":
return c.SliceUint(in.FromValue, SliceOption{})
return c.SliceUint(in.FromValue, option.SliceOption)
case "[]uint8":
return c.Bytes(in.FromValue)
case "[]uint32":
return c.SliceUint32(in.FromValue, SliceOption{})
return c.SliceUint32(in.FromValue, option.SliceOption)
case "[]uint64":
return c.SliceUint64(in.FromValue, SliceOption{})
return c.SliceUint64(in.FromValue, option.SliceOption)
case "[]float32":
return c.SliceFloat32(in.FromValue, SliceOption{})
return c.SliceFloat32(in.FromValue, option.SliceOption)
case "[]float64":
return c.SliceFloat64(in.FromValue, SliceOption{})
return c.SliceFloat64(in.FromValue, option.SliceOption)
case "[]string":
return c.SliceStr(in.FromValue, SliceOption{})
return c.SliceStr(in.FromValue, option.SliceOption)
case "Time", "time.Time":
if len(in.Extra) > 0 {
s, err := c.String(in.Extra[0])
if len(option.ExtraParams) > 0 {
s, err := c.String(option.ExtraParams[0])
if err != nil {
return nil, err
}
@ -264,8 +268,8 @@ func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err err
return c.Time(in.FromValue)
case "*time.Time":
var v time.Time
if len(in.Extra) > 0 {
s, err := c.String(in.Extra[0])
if len(option.ExtraParams) > 0 {
s, err := c.String(option.ExtraParams[0])
if err != nil {
return time.Time{}, err
}
@ -285,8 +289,8 @@ func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err err
return &v, nil
case "GTime", "gtime.Time":
if len(in.Extra) > 0 {
s, err := c.String(in.Extra[0])
if len(option.ExtraParams) > 0 {
s, err := c.String(option.ExtraParams[0])
if err != nil {
return *gtime.New(), err
}
@ -308,8 +312,8 @@ func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err err
}
return *gtime.New(), nil
case "*gtime.Time":
if len(in.Extra) > 0 {
s, err := c.String(in.Extra[0])
if len(option.ExtraParams) > 0 {
s, err := c.String(option.ExtraParams[0])
if err != nil {
return gtime.New(), err
}
@ -344,13 +348,13 @@ func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err err
return &v, nil
case "map[string]string":
return c.MapStrStr(in.FromValue, MapOption{})
return c.MapStrStr(in.FromValue, option.MapOption)
case "map[string]interface {}":
return c.Map(in.FromValue, MapOption{})
return c.Map(in.FromValue, option.MapOption)
case "[]map[string]interface {}":
return c.SliceMap(in.FromValue, SliceOption{}, MapOption{})
return c.SliceMap(in.FromValue, option.SliceOption, option.MapOption)
case "RawMessage", "json.RawMessage":
// issue 3449
@ -361,92 +365,95 @@ func (c *impConverter) doConvert(in doConvertInput) (convertedValue any, err err
return bytes, nil
default:
if in.ReferValue != nil {
var referReflectValue reflect.Value
if v, ok := in.ReferValue.(reflect.Value); ok {
referReflectValue = v
} else {
referReflectValue = reflect.ValueOf(in.ReferValue)
}
var fromReflectValue reflect.Value
if v, ok := in.FromValue.(reflect.Value); ok {
fromReflectValue = v
} else {
fromReflectValue = reflect.ValueOf(in.FromValue)
}
// custom converter.
dstReflectValue, ok, err := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue)
if err != nil {
return nil, err
}
if ok {
return dstReflectValue.Interface(), nil
}
defer func() {
if recover() != nil {
in.alreadySetToReferValue = false
if err := c.bindVarToReflectValue(referReflectValue, in.FromValue, nil); err == nil {
in.alreadySetToReferValue = true
convertedValue = referReflectValue.Interface()
}
}
}()
switch referReflectValue.Kind() {
case reflect.Ptr:
// Type converting for custom type pointers.
// Eg:
// type PayMode int
// type Req struct{
// Mode *PayMode
// }
//
// Struct(`{"Mode": 1000}`, &req)
originType := referReflectValue.Type().Elem()
switch originType.Kind() {
case reflect.Struct:
// Not support some kinds.
default:
in.ToTypeName = originType.Kind().String()
in.ReferValue = nil
result, err := c.doConvert(in)
if err != nil {
return nil, err
}
refElementValue := reflect.ValueOf(result)
originTypeValue := reflect.New(refElementValue.Type()).Elem()
originTypeValue.Set(refElementValue)
in.alreadySetToReferValue = true
return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface(), nil
}
case reflect.Map:
var targetValue = reflect.New(referReflectValue.Type()).Elem()
if err = c.MapToMap(in.FromValue, targetValue, nil, MapOption{}); err == nil {
in.alreadySetToReferValue = true
}
return targetValue.Interface(), nil
default:
}
in.ToTypeName = referReflectValue.Kind().String()
in.ReferValue = nil
in.alreadySetToReferValue = true
result, err := c.doConvert(in)
if err != nil {
return nil, err
}
convertedValue = reflect.ValueOf(result).Convert(referReflectValue.Type()).Interface()
return convertedValue, nil
}
return in.FromValue, nil
return c.doConvertForDefault(in, option)
}
}
func (c *impConverter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput) error {
convertedValue, err := c.doConvert(in)
func (c *Converter) doConvertForDefault(in doConvertInput, option ConvertOption) (convertedValue any, err error) {
if in.ReferValue != nil {
var referReflectValue reflect.Value
if v, ok := in.ReferValue.(reflect.Value); ok {
referReflectValue = v
} else {
referReflectValue = reflect.ValueOf(in.ReferValue)
}
var fromReflectValue reflect.Value
if v, ok := in.FromValue.(reflect.Value); ok {
fromReflectValue = v
} else {
fromReflectValue = reflect.ValueOf(in.FromValue)
}
// custom converter.
dstReflectValue, ok, err := c.callCustomConverterWithRefer(fromReflectValue, referReflectValue)
if err != nil {
return nil, err
}
if ok {
return dstReflectValue.Interface(), nil
}
defer func() {
if recover() != nil {
in.alreadySetToReferValue = false
if err = c.bindVarToReflectValue(referReflectValue, in.FromValue, option.StructOption); err == nil {
in.alreadySetToReferValue = true
convertedValue = referReflectValue.Interface()
}
}
}()
switch referReflectValue.Kind() {
case reflect.Ptr:
// Type converting for custom type pointers.
// Eg:
// type PayMode int
// type Req struct{
// Mode *PayMode
// }
//
// Struct(`{"Mode": 1000}`, &req)
originType := referReflectValue.Type().Elem()
switch originType.Kind() {
case reflect.Struct:
// Not support some kinds.
default:
in.ToTypeName = originType.Kind().String()
in.ReferValue = nil
result, err := c.doConvert(in, option)
if err != nil {
return nil, err
}
refElementValue := reflect.ValueOf(result)
originTypeValue := reflect.New(refElementValue.Type()).Elem()
originTypeValue.Set(refElementValue)
in.alreadySetToReferValue = true
return originTypeValue.Addr().Convert(referReflectValue.Type()).Interface(), nil
}
case reflect.Map:
var targetValue = reflect.New(referReflectValue.Type()).Elem()
if err = c.MapToMap(in.FromValue, targetValue, nil, option.MapOption); err == nil {
in.alreadySetToReferValue = true
}
return targetValue.Interface(), nil
default:
}
in.ToTypeName = referReflectValue.Kind().String()
in.ReferValue = nil
in.alreadySetToReferValue = true
result, err := c.doConvert(in, option)
if err != nil {
return nil, err
}
convertedValue = reflect.ValueOf(result).Convert(referReflectValue.Type()).Interface()
return convertedValue, nil
}
return in.FromValue, nil
}
func (c *Converter) doConvertWithReflectValueSet(reflectValue reflect.Value, in doConvertInput, option ConvertOption) error {
convertedValue, err := c.doConvert(in, option)
if err != nil {
return err
}
@ -456,7 +463,7 @@ func (c *impConverter) doConvertWithReflectValueSet(reflectValue reflect.Value,
return err
}
func (c *impConverter) getRegisteredConverterFuncAndSrcType(
func (c *Converter) getRegisteredConverterFuncAndSrcType(
srcReflectValue, dstReflectValueForRefer reflect.Value,
) (f converterFunc, srcType reflect.Type, ok bool) {
if len(c.typeConverterFuncMap) == 0 {
@ -492,7 +499,7 @@ func (c *impConverter) getRegisteredConverterFuncAndSrcType(
return
}
func (c *impConverter) callCustomConverterWithRefer(
func (c *Converter) callCustomConverterWithRefer(
srcReflectValue, referReflectValue reflect.Value,
) (dstReflectValue reflect.Value, converted bool, err error) {
registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, referReflectValue)
@ -505,7 +512,7 @@ func (c *impConverter) callCustomConverterWithRefer(
}
// callCustomConverter call the custom converter. It will try some possible type.
func (c *impConverter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) {
func (c *Converter) callCustomConverter(srcReflectValue, dstReflectValue reflect.Value) (converted bool, err error) {
registeredConverterFunc, srcType, ok := c.getRegisteredConverterFuncAndSrcType(srcReflectValue, dstReflectValue)
if !ok {
return false, nil
@ -513,7 +520,7 @@ func (c *impConverter) callCustomConverter(srcReflectValue, dstReflectValue refl
return c.doCallCustomConverter(srcReflectValue, dstReflectValue, registeredConverterFunc, srcType)
}
func (c *impConverter) doCallCustomConverter(
func (c *Converter) doCallCustomConverter(
srcReflectValue reflect.Value,
dstReflectValue reflect.Value,
registeredConverterFunc converterFunc,

View File

@ -17,7 +17,8 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *impConverter) Float32(any any) (float32, error) {
// Float32 converts `any` to float32.
func (c *Converter) Float32(any any) (float32, error) {
if empty.IsNil(any) {
return 0, nil
}
@ -78,7 +79,8 @@ func (c *impConverter) Float32(any any) (float32, error) {
}
}
func (c *impConverter) Float64(any any) (float64, error) {
// Float64 converts `any` to float64.
func (c *Converter) Float64(any any) (float64, error) {
if empty.IsNil(any) {
return 0, nil
}

View File

@ -18,7 +18,8 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *impConverter) Int(any any) (int, error) {
// Int converts `any` to int.
func (c *Converter) Int(any any) (int, error) {
if v, ok := any.(int); ok {
return v, nil
}
@ -29,7 +30,8 @@ func (c *impConverter) Int(any any) (int, error) {
return int(v), nil
}
func (c *impConverter) Int8(any any) (int8, error) {
// Int8 converts `any` to int8.
func (c *Converter) Int8(any any) (int8, error) {
if v, ok := any.(int8); ok {
return v, nil
}
@ -40,7 +42,8 @@ func (c *impConverter) Int8(any any) (int8, error) {
return int8(v), nil
}
func (c *impConverter) Int16(any any) (int16, error) {
// Int16 converts `any` to int16.
func (c *Converter) Int16(any any) (int16, error) {
if v, ok := any.(int16); ok {
return v, nil
}
@ -51,7 +54,8 @@ func (c *impConverter) Int16(any any) (int16, error) {
return int16(v), nil
}
func (c *impConverter) Int32(any any) (int32, error) {
// Int32 converts `any` to int32.
func (c *Converter) Int32(any any) (int32, error) {
if v, ok := any.(int32); ok {
return v, nil
}
@ -62,7 +66,8 @@ func (c *impConverter) Int32(any any) (int32, error) {
return int32(v), nil
}
func (c *impConverter) Int64(any any) (int64, error) {
// Int64 converts `any` to int64.
func (c *Converter) Int64(any any) (int64, error) {
if empty.IsNil(any) {
return 0, nil
}

View File

@ -30,9 +30,9 @@ type MapOption struct {
// Tags specifies the converted map key name by struct tag name.
Tags []string
// BreakOnError specifies whether to break converting the next element
// if one element conversion fails in map.
BreakOnError bool
// ContinueOnError specifies whether to continue converting the next element
// if one element converting fails.
ContinueOnError bool
}
// Map converts any variable `value` to map[string]any. If the parameter `value` is not a
@ -41,18 +41,18 @@ type MapOption struct {
// If `value` is a struct/*struct object, the second parameter `priorityTagAndFieldName` specifies the most priority
// priorityTagAndFieldName that will be detected, otherwise it detects the priorityTagAndFieldName in order of:
// gconv, json, field name.
func (c *impConverter) Map(value any, option MapOption) (map[string]any, error) {
func (c *Converter) Map(value any, option MapOption) (map[string]any, error) {
return c.doMapConvert(value, RecursiveTypeAuto, false, option)
}
// MapStrStr converts `value` to map[string]string.
// Note that there might be data copy for this map type converting.
func (c *impConverter) MapStrStr(value any, option MapOption) (map[string]string, error) {
func (c *Converter) MapStrStr(value any, option MapOption) (map[string]string, error) {
if r, ok := value.(map[string]string); ok {
return r, nil
}
m, err := c.Map(value, option)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
if len(m) > 0 {
@ -62,7 +62,7 @@ func (c *impConverter) MapStrStr(value any, option MapOption) (map[string]string
)
for k, v := range m {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
vMap[k] = s
@ -76,7 +76,7 @@ func (c *impConverter) MapStrStr(value any, option MapOption) (map[string]string
// It automatically checks and converts json string to map if `value` is string/[]byte.
//
// TODO completely implement the recursive converting for all types, especially the map.
func (c *impConverter) doMapConvert(
func (c *Converter) doMapConvert(
value any, recursive RecursiveType, mustMapReturn bool, option MapOption,
) (map[string]any, error) {
if value == nil {
@ -127,7 +127,7 @@ func (c *impConverter) doMapConvert(
recursiveOption.Tags = newTags
for k, v := range r {
s, err := c.String(k)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
dataMap[s], err = c.doMapConvertForMapOrStructValue(
@ -139,14 +139,14 @@ func (c *impConverter) doMapConvert(
Option: recursiveOption,
},
)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
}
case map[interface{}]string:
for k, v := range r {
s, err := c.String(k)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
dataMap[s] = v
@ -154,7 +154,7 @@ func (c *impConverter) doMapConvert(
case map[interface{}]int:
for k, v := range r {
s, err := c.String(k)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
dataMap[s] = v
@ -162,7 +162,7 @@ func (c *impConverter) doMapConvert(
case map[interface{}]uint:
for k, v := range r {
s, err := c.String(k)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
dataMap[s] = v
@ -170,7 +170,7 @@ func (c *impConverter) doMapConvert(
case map[interface{}]float32:
for k, v := range r {
s, err := c.String(k)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
dataMap[s] = v
@ -178,7 +178,7 @@ func (c *impConverter) doMapConvert(
case map[interface{}]float64:
for k, v := range r {
s, err := c.String(k)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
dataMap[s] = v
@ -222,7 +222,7 @@ func (c *impConverter) doMapConvert(
Option: recursiveOption,
},
)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
}
@ -235,7 +235,7 @@ func (c *impConverter) doMapConvert(
recursiveOption.Tags = newTags
for k, v := range r {
s, err := c.String(k)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
dataMap[s], err = c.doMapConvertForMapOrStructValue(
@ -247,14 +247,14 @@ func (c *impConverter) doMapConvert(
Option: recursiveOption,
},
)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
}
case map[int]string:
for k, v := range r {
s, err := c.String(k)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
dataMap[s] = v
@ -262,7 +262,7 @@ func (c *impConverter) doMapConvert(
case map[uint]string:
for k, v := range r {
s, err := c.String(k)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
dataMap[s] = v
@ -291,7 +291,7 @@ func (c *impConverter) doMapConvert(
length := reflectValue.Len()
for i := 0; i < length; i += 2 {
s, err := c.String(reflectValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
if i+1 < length {
@ -313,7 +313,7 @@ func (c *impConverter) doMapConvert(
MustMapReturn: mustMapReturn,
},
)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
if m, ok := convertedValue.(map[string]interface{}); ok {
@ -336,7 +336,7 @@ type doMapConvertForMapOrStructValueInput struct {
MustMapReturn bool // Must return map instead of Value when empty.
}
func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) (any, error) {
func (c *Converter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) (any, error) {
if !in.IsRoot && !in.RecursiveOption {
return in.Value, nil
}
@ -382,7 +382,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
mapValue = mapKeyValue.Interface()
}
s, err := c.String(mapIter.Key().Interface())
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
dataMap[s], err = c.doMapConvertForMapOrStructValue(
@ -394,7 +394,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
Option: in.Option,
},
)
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
}
@ -416,7 +416,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
Option: in.Option,
},
)
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
} else {
@ -510,7 +510,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
Option: in.Option,
},
)
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
if m, ok := anonymousValue.(map[string]interface{}); ok {
@ -532,7 +532,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
Option: in.Option,
},
)
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
@ -546,7 +546,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
Option: in.Option,
},
)
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
}
@ -569,7 +569,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
Option: in.Option,
},
)
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
}
@ -581,7 +581,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
)
for mapIter.Next() {
s, err := c.String(mapIter.Key().Interface())
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
nestedMap[s], err = c.doMapConvertForMapOrStructValue(
@ -593,7 +593,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
Option: in.Option,
},
)
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
}
@ -634,7 +634,7 @@ func (c *impConverter) doMapConvertForMapOrStructValue(in doMapConvertForMapOrSt
RecursiveOption: in.RecursiveType == RecursiveTypeTrue,
Option: in.Option,
})
if err != nil && in.Option.BreakOnError {
if err != nil && !in.Option.ContinueOnError {
return nil, err
}
}

View File

@ -23,7 +23,7 @@ import (
//
// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
// sense only if the items of original map `params` is type struct.
func (c *impConverter) MapToMap(
func (c *Converter) MapToMap(
params, pointer any, mapping map[string]string, option MapOption,
) (err error) {
var (
@ -85,6 +85,11 @@ func (c *impConverter) MapToMap(
pointerValueType = pointerRv.Type().Elem()
pointerValueKind = pointerValueType.Kind()
dataMap = reflect.MakeMapWithSize(pointerRv.Type(), len(paramsKeys))
convertOption = ConvertOption{
StructOption: StructOption{ContinueOnError: option.ContinueOnError},
SliceOption: SliceOption{ContinueOnError: option.ContinueOnError},
MapOption: option,
}
)
// Retrieve the true element type of target map.
if pointerValueKind == reflect.Ptr {
@ -94,29 +99,36 @@ func (c *impConverter) MapToMap(
mapValue := reflect.New(pointerValueType).Elem()
switch pointerValueKind {
case reflect.Map, reflect.Struct:
if err = c.Struct(
paramsRv.MapIndex(key).Interface(), mapValue, mapping, "",
); err != nil {
structOption := StructOption{
ParamKeyToAttrMap: mapping,
PriorityTag: "",
ContinueOnError: option.ContinueOnError,
}
if err = c.Struct(paramsRv.MapIndex(key).Interface(), mapValue, structOption); err != nil {
return err
}
default:
convertResult, err := c.doConvert(doConvertInput{
FromValue: paramsRv.MapIndex(key).Interface(),
ToTypeName: pointerValueType.String(),
ReferValue: mapValue,
Extra: nil,
})
convertResult, err := c.doConvert(
doConvertInput{
FromValue: paramsRv.MapIndex(key).Interface(),
ToTypeName: pointerValueType.String(),
ReferValue: mapValue,
},
convertOption,
)
if err != nil {
return err
}
mapValue.Set(reflect.ValueOf(convertResult))
}
convertResult, err := c.doConvert(doConvertInput{
FromValue: key.Interface(),
ToTypeName: pointerKeyType.Name(),
ReferValue: reflect.New(pointerKeyType).Elem().Interface(),
Extra: nil,
})
convertResult, err := c.doConvert(
doConvertInput{
FromValue: key.Interface(),
ToTypeName: pointerKeyType.Name(),
ReferValue: reflect.New(pointerKeyType).Elem().Interface(),
},
convertOption,
)
if err != nil {
return err
}

View File

@ -21,7 +21,9 @@ import (
//
// The optional parameter `mapping` is used for struct attribute to map key mapping, which makes
// sense only if the item of `params` is type struct.
func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap map[string]string) (err error) {
func (c *Converter) MapToMaps(
params any, pointer any, paramKeyToAttrMap map[string]string, option MapOption,
) (err error) {
// Params and its element type check.
var (
paramsRv reflect.Value
@ -103,13 +105,13 @@ func (c *impConverter) MapToMaps(params any, pointer any, paramKeyToAttrMap map[
var item reflect.Value
if pointerElemType.Kind() == reflect.Ptr {
item = reflect.New(pointerElemType.Elem())
if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, MapOption{}); err != nil {
if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option); err != nil {
return err
}
pointerSlice.Index(i).Set(item)
} else {
item = reflect.New(pointerElemType)
if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, MapOption{}); err != nil {
if err = c.MapToMap(paramsRv.Index(i).Interface(), item, paramKeyToAttrMap, option); err != nil {
return err
}
pointerSlice.Index(i).Set(item.Elem())

View File

@ -6,7 +6,8 @@
package converter
func (c *impConverter) Rune(any any) (rune, error) {
// Rune converts `any` to rune.
func (c *Converter) Rune(any any) (rune, error) {
if v, ok := any.(rune); ok {
return v, nil
}
@ -17,7 +18,8 @@ func (c *impConverter) Rune(any any) (rune, error) {
return v, nil
}
func (c *impConverter) Runes(any any) ([]rune, error) {
// Runes converts `any` to []rune.
func (c *Converter) Runes(any any) ([]rune, error) {
if v, ok := any.([]rune); ok {
return v, nil
}

View File

@ -15,12 +15,18 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
// ScanOption is the option for the Scan function.
type ScanOption struct {
// ParamKeyToAttrMap specifies the mapping between parameter keys and struct attribute names.
ParamKeyToAttrMap map[string]string
BreakOnError bool
// ContinueOnError specifies whether to continue converting the next element
// if one element converting fails.
ContinueOnError bool
}
func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (err error) {
// Scan automatically checks the type of `pointer` and converts `params` to `pointer`.
func (c *Converter) Scan(srcValue any, dstPointer any, option ScanOption) (err error) {
// Check if srcValue is nil, in which case no conversion is needed
if srcValue == nil {
return nil
@ -93,7 +99,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (er
}
// Check if srcValue and dstPointer are the same type, in which case direct assignment can be performed
if ok := doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem); ok {
if ok := c.doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem); ok {
return nil
}
@ -101,7 +107,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (er
switch dstPointerReflectValueElemKind {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
v, err := c.Int64(srcValue)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetInt(v)
@ -109,7 +115,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (er
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
v, err := c.Uint64(srcValue)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetUint(v)
@ -117,7 +123,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (er
case reflect.Float32, reflect.Float64:
v, err := c.Float64(srcValue)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetFloat(v)
@ -125,7 +131,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (er
case reflect.String:
v, err := c.String(srcValue)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetString(v)
@ -133,7 +139,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (er
case reflect.Bool:
v, err := c.Bool(srcValue)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
dstPointerReflectValueElem.SetBool(v)
@ -166,31 +172,31 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (er
switch dstElemType.Kind() {
case reflect.String:
v, err := c.String(srcElem)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
newSlice.Index(i).SetString(v)
case reflect.Int:
v, err := c.Int64(srcElem)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
newSlice.Index(i).SetInt(v)
case reflect.Int64:
v, err := c.Int64(srcElem)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
newSlice.Index(i).SetInt(v)
case reflect.Float64:
v, err := c.Float64(srcElem)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
newSlice.Index(i).SetFloat(v)
case reflect.Bool:
v, err := c.Bool(srcElem)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return err
}
newSlice.Index(i).SetBool(v)
@ -222,7 +228,7 @@ func (c *impConverter) Scan(srcValue any, dstPointer any, option ScanOption) (er
// - dstPointer: The destination pointer to convert to
// - dstPointerReflectType: The reflection type of the destination pointer
// - paramKeyToAttrMap: Optional mapping between parameter keys and struct attribute names
func (c *impConverter) doScanForComplicatedTypes(
func (c *Converter) doScanForComplicatedTypes(
srcValue, dstPointer any,
dstPointerReflectType reflect.Type,
option ScanOption,
@ -246,7 +252,9 @@ func (c *impConverter) doScanForComplicatedTypes(
switch dstPointerReflectTypeElemKind {
case reflect.Map:
// Convert map to map
return c.MapToMap(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{})
return c.MapToMap(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{
ContinueOnError: option.ContinueOnError,
})
case reflect.Array, reflect.Slice:
var (
@ -260,20 +268,35 @@ func (c *impConverter) doScanForComplicatedTypes(
}
if sliceElemKind == reflect.Map {
// Convert to slice of maps
return c.MapToMaps(srcValue, dstPointer, keyToAttributeNameMapping)
return c.MapToMaps(srcValue, dstPointer, keyToAttributeNameMapping, MapOption{
ContinueOnError: option.ContinueOnError,
})
}
// Convert to slice of structs
return c.Structs(srcValue, dstPointer, keyToAttributeNameMapping, "")
var (
sliceOption = SliceOption{
ContinueOnError: option.ContinueOnError,
}
mapOption = StructOption{
ParamKeyToAttrMap: keyToAttributeNameMapping,
ContinueOnError: option.ContinueOnError,
}
)
return c.Structs(srcValue, dstPointer, sliceOption, mapOption)
default:
// Convert to single struct
return c.Struct(srcValue, dstPointer, keyToAttributeNameMapping, "")
structOption := StructOption{
ParamKeyToAttrMap: keyToAttributeNameMapping,
PriorityTag: "",
ContinueOnError: option.ContinueOnError,
}
return c.Struct(srcValue, dstPointer, structOption)
}
}
// doConvertWithTypeCheck supports `pointer` in type of `*map/*[]map/*[]*map/*struct/**struct/*[]struct/*[]*struct`
// for converting.
func doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem reflect.Value) (ok bool) {
func (c *Converter) doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem reflect.Value) (ok bool) {
if !dstPointerReflectValueElem.IsValid() || !srcValueReflectValue.IsValid() {
return false
}
@ -328,7 +351,7 @@ func doConvertWithTypeCheck(srcValueReflectValue, dstPointerReflectValueElem ref
// Returns:
// - bool: true if JSON conversion was successful
// - error: any error that occurred during conversion
func (c *impConverter) doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) {
func (c *Converter) doConvertWithJsonCheck(srcValue any, dstPointer any) (ok bool, err error) {
switch valueResult := srcValue.(type) {
case []byte:
if json.Valid(valueResult) {

View File

@ -17,13 +17,13 @@ import (
// SliceOption is the option for Slice type converting.
type SliceOption struct {
// BreakOnError specifies whether to break converting the next element
// if one element conversion fails in slice.
BreakOnError bool
// ContinueOnError specifies whether to continue converting the next element
// if one element converting fails.
ContinueOnError bool
}
// SliceAny converts `any` to []any.
func (c *impConverter) SliceAny(any interface{}, option SliceOption) ([]any, error) {
func (c *Converter) SliceAny(any interface{}, option SliceOption) ([]any, error) {
if empty.IsNil(any) {
return nil, nil
}

View File

@ -17,7 +17,7 @@ import (
)
// SliceFloat32 converts `any` to []float32.
func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]float32, error) {
func (c *Converter) SliceFloat32(any interface{}, option SliceOption) ([]float32, error) {
if empty.IsNil(any) {
return nil, nil
}
@ -31,7 +31,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -40,7 +40,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -49,7 +49,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -58,7 +58,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -67,7 +67,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -76,7 +76,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -85,7 +85,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -99,7 +99,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -116,7 +116,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
}
if utils.IsNumeric(value) {
f, err = c.Float32(value)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []float32{f}, err
@ -125,7 +125,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -134,7 +134,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -143,7 +143,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -152,7 +152,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -163,7 +163,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -172,7 +172,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
array = make([]float32, len(value))
for k, v := range value {
f, err = c.Float32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -197,7 +197,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
)
for i := 0; i < length; i++ {
f, err = c.Float32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
slice[i] = f
@ -209,7 +209,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
return []float32{}, err
}
f, err = c.Float32(any)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []float32{f}, err
@ -217,7 +217,7 @@ func (c *impConverter) SliceFloat32(any interface{}, option SliceOption) ([]floa
}
// SliceFloat64 converts `any` to []float64.
func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]float64, error) {
func (c *Converter) SliceFloat64(any interface{}, option SliceOption) ([]float64, error) {
if empty.IsNil(any) {
return nil, nil
}
@ -231,7 +231,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -240,7 +240,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -249,7 +249,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -258,7 +258,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -267,7 +267,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -276,7 +276,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -285,7 +285,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -299,7 +299,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -316,7 +316,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
}
if utils.IsNumeric(value) {
f, err = c.Float64(value)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []float64{f}, err
@ -325,7 +325,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -334,7 +334,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -343,7 +343,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -352,7 +352,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -361,7 +361,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -372,7 +372,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
array = make([]float64, len(value))
for k, v := range value {
f, err = c.Float64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = f
@ -397,7 +397,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
)
for i := 0; i < length; i++ {
f, err = c.Float64(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
slice[i] = f
@ -409,7 +409,7 @@ func (c *impConverter) SliceFloat64(any interface{}, option SliceOption) ([]floa
return []float64{}, err
}
f, err = c.Float64(any)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []float64{f}, err

View File

@ -17,7 +17,7 @@ import (
)
// SliceInt converts `any` to []int.
func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
func (c *Converter) SliceInt(any any, option SliceOption) ([]int, error) {
if empty.IsNil(any) {
return nil, nil
}
@ -31,7 +31,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -85,7 +85,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
}
if utils.IsNumeric(value) {
ii, err = c.Int(value)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []int{ii}, err
@ -118,7 +118,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -127,7 +127,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -136,7 +136,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -145,7 +145,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
array = make([]int, len(value))
for k, v := range value {
ii, err = c.Int(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -170,7 +170,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
)
for i := 0; i < length; i++ {
ii, err = c.Int(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
slice[i] = ii
@ -182,7 +182,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
return []int{}, err
}
ii, err = c.Int(any)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []int{ii}, err
@ -190,7 +190,7 @@ func (c *impConverter) SliceInt(any any, option SliceOption) ([]int, error) {
}
// SliceInt32 converts `any` to []int32.
func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error) {
func (c *Converter) SliceInt32(any any, option SliceOption) ([]int32, error) {
if empty.IsNil(any) {
return nil, nil
}
@ -204,7 +204,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error)
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -258,7 +258,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error)
}
if utils.IsNumeric(value) {
ii, err = c.Int32(value)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []int32{ii}, err
@ -291,7 +291,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error)
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -300,7 +300,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error)
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -309,7 +309,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error)
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -318,7 +318,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error)
array = make([]int32, len(value))
for k, v := range value {
ii, err = c.Int32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -343,7 +343,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error)
)
for i := 0; i < length; i++ {
ii, err = c.Int32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
slice[i] = ii
@ -355,7 +355,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error)
return []int32{}, err
}
ii, err = c.Int32(any)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []int32{ii}, err
@ -363,7 +363,7 @@ func (c *impConverter) SliceInt32(any any, option SliceOption) ([]int32, error)
}
// SliceInt64 converts `any` to []int64.
func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error) {
func (c *Converter) SliceInt64(any any, option SliceOption) ([]int64, error) {
if empty.IsNil(any) {
return nil, nil
}
@ -377,7 +377,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error)
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -431,7 +431,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error)
}
if utils.IsNumeric(value) {
ii, err = c.Int64(value)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []int64{ii}, err
@ -464,7 +464,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error)
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -473,7 +473,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error)
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -482,7 +482,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error)
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -491,7 +491,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error)
array = make([]int64, len(value))
for k, v := range value {
ii, err = c.Int64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ii
@ -516,7 +516,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error)
)
for i := 0; i < length; i++ {
ii, err = c.Int64(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
slice[i] = ii
@ -528,7 +528,7 @@ func (c *impConverter) SliceInt64(any any, option SliceOption) ([]int64, error)
return []int64{}, err
}
ii, err = c.Int64(any)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []int64{ii}, err

View File

@ -10,7 +10,7 @@ import "github.com/gogf/gf/v2/internal/json"
// SliceMap converts `value` to []map[string]any.
// Note that it automatically checks and converts json string to []map if `value` is string/[]byte.
func (c *impConverter) SliceMap(value any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error) {
func (c *Converter) SliceMap(value any, sliceOption SliceOption, mapOption MapOption) ([]map[string]any, error) {
if value == nil {
return nil, nil
}
@ -49,7 +49,7 @@ func (c *impConverter) SliceMap(value any, sliceOption SliceOption, mapOption Ma
list := make([]map[string]any, len(array))
for k, v := range array {
m, err := c.Map(v, mapOption)
if err != nil && sliceOption.BreakOnError {
if err != nil && !sliceOption.ContinueOnError {
return nil, err
}
list[k] = m

View File

@ -16,7 +16,7 @@ import (
)
// SliceStr converts `any` to []string.
func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string, error) {
func (c *Converter) SliceStr(any interface{}, option SliceOption) ([]string, error) {
if empty.IsNil(any) {
return nil, nil
}
@ -30,7 +30,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -39,7 +39,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -48,7 +48,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -57,7 +57,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -66,7 +66,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -75,7 +75,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -89,7 +89,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -110,7 +110,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -119,7 +119,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -128,7 +128,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -137,7 +137,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -146,7 +146,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -155,7 +155,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -164,7 +164,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -175,7 +175,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
array = make([]string, len(value))
for k, v := range value {
s, err = c.String(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = s
@ -200,7 +200,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
)
for i := 0; i < length; i++ {
s, err = c.String(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
slice[i] = s
@ -212,7 +212,7 @@ func (c *impConverter) SliceStr(any interface{}, option SliceOption) ([]string,
return []string{}, err
}
s, err = c.String(any)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []string{s}, err

View File

@ -17,7 +17,7 @@ import (
)
// SliceUint converts `any` to []uint.
func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, error) {
func (c *Converter) SliceUint(any interface{}, option SliceOption) ([]uint, error) {
if empty.IsNil(any) {
return nil, nil
}
@ -31,7 +31,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -80,7 +80,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e
}
if utils.IsNumeric(value) {
ui, err = c.Uint(value)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []uint{ui}, err
@ -113,7 +113,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -122,7 +122,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -131,7 +131,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -140,7 +140,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e
array = make([]uint, len(value))
for k, v := range value {
ui, err = c.Uint(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -168,7 +168,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e
)
for i := 0; i < length; i++ {
ui, err = c.Uint(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
slice[i] = ui
@ -180,7 +180,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e
return []uint{}, err
}
ui, err = c.Uint(any)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []uint{ui}, err
@ -188,7 +188,7 @@ func (c *impConverter) SliceUint(any interface{}, option SliceOption) ([]uint, e
}
// SliceUint32 converts `any` to []uint32.
func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint32, error) {
func (c *Converter) SliceUint32(any interface{}, option SliceOption) ([]uint32, error) {
if empty.IsNil(any) {
return nil, nil
}
@ -202,7 +202,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -254,7 +254,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3
}
if utils.IsNumeric(value) {
ui, err = c.Uint32(value)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []uint32{ui}, err
@ -284,7 +284,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -293,7 +293,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -302,7 +302,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -311,7 +311,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3
array = make([]uint32, len(value))
for k, v := range value {
ui, err = c.Uint32(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -338,7 +338,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3
)
for i := 0; i < length; i++ {
ui, err = c.Uint32(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
slice[i] = ui
@ -350,7 +350,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3
return []uint32{}, err
}
ui, err = c.Uint32(any)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []uint32{ui}, err
@ -358,7 +358,7 @@ func (c *impConverter) SliceUint32(any interface{}, option SliceOption) ([]uint3
}
// SliceUint64 converts `any` to []uint64.
func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint64, error) {
func (c *Converter) SliceUint64(any interface{}, option SliceOption) ([]uint64, error) {
if empty.IsNil(any) {
return nil, nil
}
@ -372,7 +372,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -424,7 +424,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6
}
if utils.IsNumeric(value) {
ui, err = c.Uint64(value)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []uint64{ui}, err
@ -454,7 +454,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -463,7 +463,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -472,7 +472,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -481,7 +481,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6
array = make([]uint64, len(value))
for k, v := range value {
ui, err = c.Uint64(v)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
array[k] = ui
@ -507,7 +507,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6
)
for i := 0; i < length; i++ {
ui, err = c.Uint64(originValueAndKind.OriginValue.Index(i).Interface())
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
slice[i] = ui
@ -519,7 +519,7 @@ func (c *impConverter) SliceUint64(any interface{}, option SliceOption) ([]uint6
return []uint64{}, err
}
ui, err = c.Uint64(any)
if err != nil && option.BreakOnError {
if err != nil && !option.ContinueOnError {
return nil, err
}
return []uint64{ui}, err

View File

@ -20,7 +20,7 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/localinterface"
)
func (c *impConverter) String(any any) (string, error) {
func (c *Converter) String(any any) (string, error) {
if empty.IsNil(any) {
return "", nil
}

View File

@ -19,13 +19,21 @@ import (
"github.com/gogf/gf/v2/util/gconv/internal/structcache"
)
// StructOption is the option for Struct converting.
type StructOption struct {
// ParamKeyToAttrMap is the map for custom parameter key to attribute name mapping.
ParamKeyToAttrMap map[string]string
// PriorityTag is the priority tag for struct converting.
PriorityTag string
// ContinueOnError specifies whether to continue converting the next element
// if one element converting fails.
ContinueOnError bool
}
// Struct is the core internal converting function for any data to struct.
func (c *impConverter) Struct(
params any,
pointer any,
paramKeyToAttrMap map[string]string,
priorityTag string,
) (err error) {
func (c *Converter) Struct(params, pointer any, option StructOption) (err error) {
if params == nil {
// If `params` is nil, no conversion.
return nil
@ -92,7 +100,7 @@ func (c *impConverter) Struct(
// If `params` and `pointer` are the same type, the do directly assignment.
// For performance enhancement purpose.
if ok = doConvertWithTypeCheck(paramsReflectValue, pointerElemReflectValue); ok {
if ok = c.doConvertWithTypeCheck(paramsReflectValue, pointerElemReflectValue); ok {
return nil
}
@ -133,7 +141,9 @@ func (c *impConverter) Struct(
if !ok {
// paramsMap is the map[string]any type variable for params.
// DO NOT use MapDeep here.
paramsMap, err = c.doMapConvert(paramsInterface, RecursiveTypeAuto, true, MapOption{})
paramsMap, err = c.doMapConvert(paramsInterface, RecursiveTypeAuto, true, MapOption{
ContinueOnError: option.ContinueOnError,
})
if err != nil {
return err
}
@ -151,7 +161,7 @@ func (c *impConverter) Struct(
}
// Get struct info from cache or parse struct and cache the struct info.
cachedStructInfo := c.internalConverter.GetCachedStructInfo(
pointerElemReflectValue.Type(), priorityTag,
pointerElemReflectValue.Type(), option.PriorityTag,
)
// Nothing to be converted.
if cachedStructInfo == nil {
@ -172,7 +182,7 @@ func (c *impConverter) Struct(
// Firstly, search according to custom mapping rules.
// If a possible direct assignment is found, reduce the number of subsequent map searches.
for paramKey, fieldName := range paramKeyToAttrMap {
for paramKey, fieldName := range option.ParamKeyToAttrMap {
paramsValue, ok = paramsMap[paramKey]
if !ok {
continue
@ -184,13 +194,13 @@ func (c *impConverter) Struct(
cachedFieldInfo,
fieldValue,
paramsValue,
paramKeyToAttrMap,
option,
); err != nil {
return err
}
if len(cachedFieldInfo.OtherSameNameField) > 0 {
if err = c.setOtherSameNameField(
cachedFieldInfo, paramsValue, pointerReflectValue, paramKeyToAttrMap,
cachedFieldInfo, paramsValue, pointerReflectValue, option,
); err != nil {
return err
}
@ -203,32 +213,34 @@ func (c *impConverter) Struct(
return nil
}
return c.bindStructWithLoopFieldInfos(
paramsMap, pointerElemReflectValue, paramKeyToAttrMap, usedParamsKeyOrTagNameMap, cachedStructInfo,
paramsMap, pointerElemReflectValue,
usedParamsKeyOrTagNameMap, cachedStructInfo,
option,
)
}
func (c *impConverter) setOtherSameNameField(
func (c *Converter) setOtherSameNameField(
cachedFieldInfo *structcache.CachedFieldInfo,
srcValue any,
structValue reflect.Value,
paramKeyToAttrMap map[string]string,
option StructOption,
) (err error) {
// loop the same field name of all sub attributes.
for _, otherFieldInfo := range cachedFieldInfo.OtherSameNameField {
fieldValue := cachedFieldInfo.GetOtherFieldReflectValueFrom(structValue, otherFieldInfo.FieldIndexes)
if err = c.bindVarToStructField(otherFieldInfo, fieldValue, srcValue, paramKeyToAttrMap); err != nil {
if err = c.bindVarToStructField(otherFieldInfo, fieldValue, srcValue, option); err != nil {
return err
}
}
return nil
}
func (c *impConverter) bindStructWithLoopFieldInfos(
func (c *Converter) bindStructWithLoopFieldInfos(
paramsMap map[string]any,
structValue reflect.Value,
paramKeyToAttrMap map[string]string,
usedParamsKeyOrTagNameMap map[string]struct{},
cachedStructInfo *structcache.CachedStructInfo,
option StructOption,
) (err error) {
var (
cachedFieldInfo *structcache.CachedFieldInfo
@ -246,15 +258,15 @@ func (c *impConverter) bindStructWithLoopFieldInfos(
}
fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue)
if err = c.bindVarToStructField(
cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap,
); err != nil {
cachedFieldInfo, fieldValue, paramValue, option,
); err != nil && !option.ContinueOnError {
return err
}
// handle same field name in nested struct.
if len(cachedFieldInfo.OtherSameNameField) > 0 {
if err = c.setOtherSameNameField(
cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap,
); err != nil {
cachedFieldInfo, paramValue, structValue, option,
); err != nil && !option.ContinueOnError {
return err
}
}
@ -279,15 +291,15 @@ func (c *impConverter) bindStructWithLoopFieldInfos(
fieldValue = cachedFieldInfo.GetFieldReflectValueFrom(structValue)
if paramValue != nil {
if err = c.bindVarToStructField(
cachedFieldInfo, fieldValue, paramValue, paramKeyToAttrMap,
); err != nil {
cachedFieldInfo, fieldValue, paramValue, option,
); err != nil && !option.ContinueOnError {
return err
}
// handle same field name in nested struct.
if len(cachedFieldInfo.OtherSameNameField) > 0 {
if err = c.setOtherSameNameField(
cachedFieldInfo, paramValue, structValue, paramKeyToAttrMap,
); err != nil {
cachedFieldInfo, paramValue, structValue, option,
); err != nil && !option.ContinueOnError {
return err
}
}
@ -319,11 +331,11 @@ func fuzzyMatchingFieldName(
// bindVarToStructField sets value to struct object attribute by name.
// each value to attribute converting comes into in this function.
func (c *impConverter) bindVarToStructField(
func (c *Converter) bindVarToStructField(
cachedFieldInfo *structcache.CachedFieldInfo,
fieldValue reflect.Value,
srcValue any,
paramKeyToAttrMap map[string]string,
option StructOption,
) (err error) {
if !fieldValue.IsValid() {
return nil
@ -334,7 +346,7 @@ func (c *impConverter) bindVarToStructField(
}
defer func() {
if exception := recover(); exception != nil {
if err = c.bindVarToReflectValue(fieldValue, srcValue, paramKeyToAttrMap); err != nil {
if err = c.bindVarToReflectValue(fieldValue, srcValue, option); err != nil {
err = gerror.Wrapf(err, `error binding srcValue to attribute "%s"`, cachedFieldInfo.FieldName())
}
}
@ -350,7 +362,7 @@ func (c *impConverter) bindVarToStructField(
customConverterInput reflect.Value
ok bool
)
if cachedFieldInfo.IsCustomConvert {
if cachedFieldInfo.HasCustomConvert {
if customConverterInput, ok = srcValue.(reflect.Value); !ok {
customConverterInput = reflect.ValueOf(srcValue)
}
@ -367,14 +379,20 @@ func (c *impConverter) bindVarToStructField(
if cachedFieldInfo.ConvertFunc != nil {
return cachedFieldInfo.ConvertFunc(srcValue, fieldValue)
}
c.doConvertWithReflectValueSet(
convertOption := ConvertOption{
StructOption: option,
SliceOption: SliceOption{ContinueOnError: option.ContinueOnError},
MapOption: MapOption{ContinueOnError: option.ContinueOnError},
}
err = c.doConvertWithReflectValueSet(
fieldValue, doConvertInput{
FromValue: srcValue,
ToTypeName: cachedFieldInfo.StructField.Type.String(),
ReferValue: fieldValue,
},
convertOption,
)
return nil
return err
}
// bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks.
@ -442,9 +460,7 @@ func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value a
}
// bindVarToReflectValue sets `value` to reflect value object `structFieldValue`.
func (c *impConverter) bindVarToReflectValue(
structFieldValue reflect.Value, value any, paramKeyToAttrMap map[string]string,
) (err error) {
func (c *Converter) bindVarToReflectValue(structFieldValue reflect.Value, value any, option StructOption) (err error) {
// JSON content converting.
ok, err := c.doConvertWithJsonCheck(value, structFieldValue)
if err != nil {
@ -470,11 +486,13 @@ func (c *impConverter) bindVarToReflectValue(
// Converting using reflection by kind.
switch kind {
case reflect.Map:
return c.MapToMap(value, structFieldValue, paramKeyToAttrMap, MapOption{})
return c.MapToMap(value, structFieldValue, option.ParamKeyToAttrMap, MapOption{
ContinueOnError: option.ContinueOnError,
})
case reflect.Struct:
// Recursively converting for struct attribute.
if err = c.Struct(value, structFieldValue, nil, ""); err != nil {
if err = c.Struct(value, structFieldValue, option); err != nil {
// Note there's reflect conversion mechanism here.
structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
}
@ -483,8 +501,13 @@ func (c *impConverter) bindVarToReflectValue(
// so it uses Struct function doing the converting internally.
case reflect.Slice, reflect.Array:
var (
reflectArray reflect.Value
reflectValue = reflect.ValueOf(value)
reflectArray reflect.Value
reflectValue = reflect.ValueOf(value)
convertOption = ConvertOption{
StructOption: option,
SliceOption: SliceOption{ContinueOnError: option.ContinueOnError},
MapOption: MapOption{ContinueOnError: option.ContinueOnError},
}
)
if reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array {
reflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len())
@ -507,7 +530,7 @@ func (c *impConverter) bindVarToReflectValue(
elem = reflect.New(elemType).Elem()
}
if elem.Kind() == reflect.Struct {
if err = c.Struct(reflectValue.Index(i).Interface(), elem, nil, ""); err == nil {
if err = c.Struct(reflectValue.Index(i).Interface(), elem, option); err == nil {
converted = true
}
}
@ -518,6 +541,7 @@ func (c *impConverter) bindVarToReflectValue(
ToTypeName: elemTypeName,
ReferValue: elem,
},
convertOption,
)
if err != nil {
return err
@ -564,7 +588,7 @@ func (c *impConverter) bindVarToReflectValue(
elem = reflect.New(elemType).Elem()
}
if elem.Kind() == reflect.Struct {
if err = c.Struct(value, elem, nil, ""); err == nil {
if err = c.Struct(value, elem, option); err == nil {
converted = true
}
}
@ -575,6 +599,7 @@ func (c *impConverter) bindVarToReflectValue(
ToTypeName: elemTypeName,
ReferValue: elem,
},
convertOption,
)
if err != nil {
return err
@ -598,12 +623,12 @@ func (c *impConverter) bindVarToReflectValue(
return err
}
elem := item.Elem()
if err = c.bindVarToReflectValue(elem, value, paramKeyToAttrMap); err == nil {
if err = c.bindVarToReflectValue(elem, value, option); err == nil {
structFieldValue.Set(elem.Addr())
}
} else {
// Not empty pointer, it assigns values to it.
return c.bindVarToReflectValue(structFieldValue.Elem(), value, paramKeyToAttrMap)
return c.bindVarToReflectValue(structFieldValue.Elem(), value, option)
}
// It mainly and specially handles the interface of nil value.

View File

@ -20,8 +20,8 @@ import (
// The parameter `pointer` should be type of pointer to slice of struct.
// Note that if `pointer` is a pointer to another pointer of type of slice of struct,
// it will create the struct/pointer internally.
func (c *impConverter) Structs(
params any, pointer any, paramKeyToAttrMap map[string]string, priorityTag string,
func (c *Converter) Structs(
params any, pointer any, sliceOption SliceOption, structOption StructOption,
) (err error) {
defer func() {
// Catch the panic, especially the reflection operation panics.
@ -62,7 +62,9 @@ func (c *impConverter) Structs(
paramsList[i] = paramsRv.Index(i).Interface()
}
default:
paramsMaps, err := c.SliceMap(params, SliceOption{}, MapOption{})
paramsMaps, err := c.SliceMap(params, sliceOption, MapOption{
ContinueOnError: structOption.ContinueOnError,
})
if err != nil {
return err
}
@ -93,7 +95,7 @@ func (c *impConverter) Structs(
if !tempReflectValue.IsValid() {
tempReflectValue = reflect.New(itemType.Elem()).Elem()
}
if err = c.Struct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil {
if err = c.Struct(paramsList[i], tempReflectValue, structOption); err != nil {
return err
}
reflectElemArray.Index(i).Set(tempReflectValue.Addr())
@ -107,7 +109,7 @@ func (c *impConverter) Structs(
} else {
tempReflectValue = reflect.New(itemType).Elem()
}
if err = c.Struct(paramsList[i], tempReflectValue, paramKeyToAttrMap, priorityTag); err != nil {
if err = c.Struct(paramsList[i], tempReflectValue, structOption); err != nil {
return err
}
reflectElemArray.Index(i).Set(tempReflectValue)

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